Files
2026-08-27 11:22:37 -06:00

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()