165 lines
5.9 KiB
Python
165 lines
5.9 KiB
Python
"""
|
|||
|
|
Hook AnyDesk backend process — monitors file I/O, bitmaps, clipboard.
|
||
|
|
Usage: python hook_backend.py <PID>
|
||
|
|
Must run as Administrator (backend runs as SYSTEM).
|
||
|
|
"""
|
||
|
|
import frida
|
||
|
|
import sys
|
||
|
|
import time
|
||
|
|
import json
|
||
|
|
from datetime import datetime
|
||
|
|
|
||
|
|
AGENT = r"""
|
||
|
|
var hc = 0;
|
||
|
|
|
||
|
|
function gx(mod, name) {
|
||
|
|
try { var m = Process.findModuleByName(mod); return m ? m.findExportByName(name) : null; }
|
||
|
|
catch(e) { return null; }
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- CreateFileW ---
|
||
|
|
var a1 = gx('KERNEL32.DLL', 'CreateFileW');
|
||
|
|
if (a1) { Interceptor.attach(a1, { onEnter: function(args) { try {
|
||
|
|
var path = args[0].readUtf16String(); if (!path) return;
|
||
|
|
var pl = path.toLowerCase();
|
||
|
|
if (pl.indexOf('\\device\\')!==-1||pl.indexOf('\\pipe\\')!==-1||pl.indexOf('condrv')!==-1) return;
|
||
|
|
var access = args[1].toInt32()>>>0, disp = args[4].toInt32();
|
||
|
|
var isW = (access&0x40000000)!==0||(access&0x2)!==0;
|
||
|
|
var isC = disp===1||disp===2||disp===4;
|
||
|
|
var fl=[];
|
||
|
|
if(path.indexOf('..\\')!==-1) fl.push('TRAV_BS');
|
||
|
|
if(path.indexOf('../')!==-1) fl.push('TRAV_FS');
|
||
|
|
if(pl.indexOf('startup')!==-1) fl.push('STARTUP');
|
||
|
|
send({t:'F', path:path, w:isW, c:isC, fl:fl});
|
||
|
|
} catch(e){} }}); hc++; }
|
||
|
|
|
||
|
|
// --- WriteFile ---
|
||
|
|
var a2 = gx('KERNEL32.DLL', 'WriteFile');
|
||
|
|
if (a2) { Interceptor.attach(a2, { onEnter: function(args) { try {
|
||
|
|
var sz = args[2].toInt32();
|
||
|
|
if (sz > 32) {
|
||
|
|
var preview = args[1].readByteArray(Math.min(sz, 128));
|
||
|
|
var arr = new Uint8Array(preview);
|
||
|
|
var str = '';
|
||
|
|
for (var i = 0; i < Math.min(arr.length, 128); i++) {
|
||
|
|
var b = arr[i];
|
||
|
|
str += (b >= 0x20 && b < 0x7f) ? String.fromCharCode(b) : '.';
|
||
|
|
}
|
||
|
|
send({t:'W', sz:sz, preview:str});
|
||
|
|
}
|
||
|
|
} catch(e){} }}); hc++; }
|
||
|
|
|
||
|
|
// --- MoveFileExW ---
|
||
|
|
var a3 = gx('KERNEL32.DLL', 'MoveFileExW');
|
||
|
|
if (a3) { Interceptor.attach(a3, { onEnter: function(args) { try {
|
||
|
|
send({t:'M', src:args[0].readUtf16String(), dst:args[1].readUtf16String()});
|
||
|
|
} catch(e){} }}); hc++; }
|
||
|
|
|
||
|
|
// --- CreateDIBSection (DeskRT output) ---
|
||
|
|
var a4 = gx('GDI32.dll', 'CreateDIBSection');
|
||
|
|
if (a4) { Interceptor.attach(a4, { onEnter: function(args) { try {
|
||
|
|
var p = args[1]; if (p.isNull()) return;
|
||
|
|
var w=p.add(4).readS32(), h=p.add(8).readS32(), bpp=p.add(14).readU16();
|
||
|
|
send({t:'B', w:w, h:h, bpp:bpp, alloc:Math.abs(w)*Math.abs(h)*(bpp/8)});
|
||
|
|
} catch(e){} }}); hc++; }
|
||
|
|
|
||
|
|
// --- Clipboard ---
|
||
|
|
var a5 = gx('USER32.dll', 'SetClipboardData');
|
||
|
|
if (a5) { Interceptor.attach(a5, { onEnter: function(args) {
|
||
|
|
send({t:'C', op:'SET', fmt:args[0].toInt32()});
|
||
|
|
}}); hc++; }
|
||
|
|
var a6 = gx('USER32.dll', 'GetClipboardData');
|
||
|
|
if (a6) { Interceptor.attach(a6, { onEnter: function(args) { this.f=args[0].toInt32(); },
|
||
|
|
onLeave: function(r) { if(!r.isNull()) send({t:'C', op:'GET', fmt:this.f}); }
|
||
|
|
}); hc++; }
|
||
|
|
|
||
|
|
// --- send/recv on backend too ---
|
||
|
|
var sc=0, rc=0;
|
||
|
|
var a7 = gx('WS2_32.dll', 'send');
|
||
|
|
if (a7) { Interceptor.attach(a7, { onLeave: function(r) { var n=r.toInt32(); if(n>0){sc++;if(sc<=10||sc%50===0)send({t:'N',d:'S',sz:n,n:sc});}}}); hc++; }
|
||
|
|
var a8 = gx('WS2_32.dll', 'recv');
|
||
|
|
if (a8) { Interceptor.attach(a8, { onLeave: function(r) { var n=r.toInt32(); if(n>0){rc++;if(rc<=10||rc%50===0)send({t:'N',d:'R',sz:n,n:rc});}}}); hc++; }
|
||
|
|
|
||
|
|
send({t:'log', m:hc+' hooks on backend'});
|
||
|
|
"""
|
||
|
|
|
||
|
|
def main():
|
||
|
|
if len(sys.argv) < 2:
|
||
|
|
print("Usage: python hook_backend.py <PID>")
|
||
|
|
print("Run as Administrator!")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
pid = int(sys.argv[1])
|
||
|
|
print(f"[+] Attaching to backend PID {pid}...")
|
||
|
|
|
||
|
|
cfn = {1:'TEXT',2:'BITMAP',8:'DIB',13:'UNICODE',15:'HDROP',17:'DIBV5'}
|
||
|
|
t0 = time.time()
|
||
|
|
events = []
|
||
|
|
|
||
|
|
def on_msg(msg, data):
|
||
|
|
if msg['type'] != 'send':
|
||
|
|
print(f" [!] {msg.get('description','error')}")
|
||
|
|
return
|
||
|
|
p = msg['payload']
|
||
|
|
t = p.get('t','')
|
||
|
|
ts = time.time() - t0
|
||
|
|
|
||
|
|
if t == 'log':
|
||
|
|
print(f" [*] {p['m']}")
|
||
|
|
elif t == 'F':
|
||
|
|
fl = ' '.join(f'[{f}]' for f in p.get('fl',[]))
|
||
|
|
mode = ('W' if p['w'] else 'R') + ('+C' if p['c'] else '')
|
||
|
|
print(f" [{ts:7.2f}s] [FILE {mode:4s}] {p['path']} {fl}")
|
||
|
|
events.append(p)
|
||
|
|
elif t == 'W':
|
||
|
|
# Only show interesting writes (not log lines)
|
||
|
|
if 'info 2026' not in p['preview'] and 'warning 2026' not in p['preview']:
|
||
|
|
print(f" [{ts:7.2f}s] [WRITE {p['sz']:6d}b] {p['preview'][:80]}")
|
||
|
|
events.append(p)
|
||
|
|
elif t == 'M':
|
||
|
|
print(f" [{ts:7.2f}s] [MOVE] {p['src']} -> {p['dst']}")
|
||
|
|
events.append(p)
|
||
|
|
elif t == 'B':
|
||
|
|
print(f" [{ts:7.2f}s] [BITMAP] {p['w']}x{p['h']} @{p['bpp']}bpp ({p['alloc']:,.0f}b)")
|
||
|
|
events.append(p)
|
||
|
|
elif t == 'C':
|
||
|
|
fn = cfn.get(p['fmt'], f"FMT{p['fmt']}")
|
||
|
|
print(f" [{ts:7.2f}s] [CLIP] {p['op']} {fn}")
|
||
|
|
events.append(p)
|
||
|
|
elif t == 'N':
|
||
|
|
print(f" [{ts:7.2f}s] [NET] {p['d']} {p['sz']}b #{p['n']}")
|
||
|
|
|
||
|
|
try:
|
||
|
|
session = frida.attach(pid)
|
||
|
|
except Exception as e:
|
||
|
|
print(f"[!] Failed: {e}")
|
||
|
|
print("[!] Run as Administrator — backend runs as SYSTEM")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
script = session.create_script(AGENT, runtime='v8')
|
||
|
|
script.on('message', on_msg)
|
||
|
|
script.load()
|
||
|
|
time.sleep(1)
|
||
|
|
|
||
|
|
print(f"\n{'='*60}")
|
||
|
|
print(" Backend hooked. Now:")
|
||
|
|
print(" 1. Use AnyDesk file transfer to send a file")
|
||
|
|
print(" 2. Copy/paste between machines")
|
||
|
|
print(" 3. Move mouse (DeskRT frames)")
|
||
|
|
print(" Ctrl+C to stop")
|
||
|
|
print(f"{'='*60}\n")
|
||
|
|
|
||
|
|
try:
|
||
|
|
while True: time.sleep(0.1)
|
||
|
|
except KeyboardInterrupt:
|
||
|
|
print("\n[+] Stopping...")
|
||
|
|
|
||
|
|
out = f"backend_{pid}_{datetime.now().strftime('%H%M%S')}.json"
|
||
|
|
with open(out, 'w') as f:
|
||
|
|
json.dump(events, f, indent=2)
|
||
|
|
print(f"[+] {len(events)} events -> {out}")
|
||
|
|
session.detach()
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
main()
|