""" AnyDesk Sniffer v4 — hooks ALL AnyDesk processes """ import frida import sys import os import json import time import subprocess from datetime import datetime CAPTURE_DIR = "captures" AGENT_CODE = r""" var hookCount = 0; function getExport(mod, name) { try { var m = Process.findModuleByName(mod); if (!m) return null; return m.findExportByName(name); } catch(e) { return null; } } function analyzeBuffer(arr, len) { var tags = []; var run = 0, maxRun = 0, bestStr = '', curStr = ''; for (var i = 0; i < len; i++) { var b = arr[i]; if (b >= 0x20 && b < 0x7f) { run++; curStr += String.fromCharCode(b); } else { if (run > maxRun) { maxRun = run; bestStr = curStr; } run = 0; curStr = ''; } } if (run > maxRun) { maxRun = run; bestStr = curStr; } if (maxRun > 10) tags.push('STR:' + bestStr.substring(0, 80)); if (len >= 8 && arr[0]===0x89 && arr[1]===0x50 && arr[2]===0x4E && arr[3]===0x47) tags.push('PNG'); if (len >= 2 && arr[0]===0x42 && arr[1]===0x4D) tags.push('BMP'); return tags; } // ---- FILE I/O ---- var p1 = getExport('KERNEL32.DLL', 'CreateFileW'); if (p1) { Interceptor.attach(p1, { 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||pl.indexOf('\\registry')!==-1) return; var access = args[1].toInt32()>>>0, disp = args[4].toInt32(); var isW = (access&0x40000000)!==0||(access&0x2)!==0, isC = disp===1||disp===2||disp===4; if (isW||isC||pl.indexOf('anydesk')!==-1||pl.indexOf('..')!==-1||pl.indexOf('desktop')!==-1||pl.indexOf('download')!==-1||pl.indexOf('startup')!==-1) { 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:'file',op:'Create',path:path,w:isW,c:isC,fl:fl,ts:Date.now()}); }} catch(e){} }}); hookCount++; } var p2 = getExport('KERNEL32.DLL', 'MoveFileExW'); if(p2){Interceptor.attach(p2,{onEnter:function(args){try{send({t:'move',src:args[0].readUtf16String(),dst:args[1].readUtf16String(),ts:Date.now()});}catch(e){}}});hookCount++;} var p3 = getExport('KERNEL32.DLL', 'CopyFileW'); if(p3){Interceptor.attach(p3,{onEnter:function(args){try{send({t:'copy',src:args[0].readUtf16String(),dst:args[1].readUtf16String(),ts:Date.now()});}catch(e){}}});hookCount++;} var p4 = getExport('KERNEL32.DLL', 'CreateDirectoryW'); if(p4){Interceptor.attach(p4,{onEnter:function(args){try{send({t:'mkdir',path:args[0].readUtf16String(),ts:Date.now()});}catch(e){}}});hookCount++;} // ---- WriteFile ---- var p5 = getExport('KERNEL32.DLL', 'WriteFile'); if(p5){ var wc=0; Interceptor.attach(p5,{onEnter:function(args){ this.sz=args[2].toInt32(); if(this.sz>64&&wc<300){wc++;try{ var preview=args[1].readByteArray(Math.min(this.sz,64));var arr=new Uint8Array(preview); var tags=analyzeBuffer(arr,arr.length);if(tags.length>0)send({t:'write',sz:this.sz,tags:tags,ts:Date.now()}); }catch(e){}}}}); hookCount++; } // ---- GDI Bitmaps ---- var p6 = getExport('GDI32.dll', 'CreateDIBSection'); if(p6){Interceptor.attach(p6,{onEnter:function(args){try{var pbmi=args[1];if(pbmi.isNull())return; var w=pbmi.add(4).readS32(),h=pbmi.add(8).readS32(),bpp=pbmi.add(14).readU16(); var alloc=Math.abs(w)*Math.abs(h)*(bpp/8); send({t:'bmp',op:'DIB',w:w,h:h,bpp:bpp,alloc:alloc,ts:Date.now()}); if(Math.abs(w)>8192||Math.abs(h)>8192)send({t:'alert',m:'HUGE BMP '+w+'x'+h+'@'+bpp}); }catch(e){}}});hookCount++;} var p7 = getExport('GDI32.dll', 'CreateCompatibleBitmap'); if(p7){Interceptor.attach(p7,{onEnter:function(args){var cx=args[1].toInt32(),cy=args[2].toInt32(); if(cx>0&&cy>0)send({t:'bmp',op:'Compat',w:cx,h:cy,bpp:0,alloc:0,ts:Date.now()});}});hookCount++;} // ---- Clipboard ---- var p8=getExport('USER32.dll','SetClipboardData'),p9=getExport('USER32.dll','GetClipboardData'); var cfn={1:'TEXT',2:'BITMAP',7:'OEM',8:'DIB',13:'UNICODE',15:'HDROP',17:'DIBV5'}; if(p8){Interceptor.attach(p8,{onEnter:function(args){var f=args[0].toInt32();send({t:'clip',op:'SET',fmt:f,name:cfn[f]||('C'+f),ts:Date.now()});}});hookCount++;} if(p9){Interceptor.attach(p9,{onEnter:function(args){this.f=args[0].toInt32();},onLeave:function(ret){if(!ret.isNull())send({t:'clip',op:'GET',fmt:this.f,name:cfn[this.f]||('C'+this.f),ts:Date.now()});}});hookCount++;} // ---- ALL socket functions ---- var sc=0,rc=0,wsc=0,wrc=0; var pS=getExport('WS2_32.dll','send'); if(pS){Interceptor.attach(pS,{onLeave:function(ret){var n=ret.toInt32();if(n>0){sc++;if(sc<=30||sc%100===0)send({t:'net',d:'S',sz:n,n:sc,ts:Date.now()});}}});hookCount++;} var pR=getExport('WS2_32.dll','recv'); if(pR){Interceptor.attach(pR,{onLeave:function(ret){var n=ret.toInt32();if(n>0){rc++;if(rc<=30||rc%100===0)send({t:'net',d:'R',sz:n,n:rc,ts:Date.now()});}}});hookCount++;} var pWS=getExport('WS2_32.dll','WSASend'); if(pWS){Interceptor.attach(pWS,{onEnter:function(args){try{var nBufs=args[2].toInt32(),lpBufs=args[1],total=0; for(var i=0;i>>0;},onLeave:function(ret){ if(this.sz>50*1024*1024)send({t:'alert',m:'BIG ALLOC '+(this.sz/1024/1024).toFixed(1)+'MB',ts:Date.now()});}});hookCount++;} setInterval(function(){send({t:'stats',s:sc,r:rc,ws:wsc,wr:wrc,ts:Date.now()});},10000); send({t:'log',m:hookCount+' hooks OK'}); send({t:'ready'}); """ class Capture: def __init__(self, d): self.d = d; os.makedirs(d, exist_ok=True) self.ev = []; self.ready_count = 0; self.t0 = time.time() def on_msg(self, pid, msg, data): if msg['type'] == 'send': p = msg['payload'] t = p.get('t','') ts = (p.get('ts', self.t0*1000)/1000) - self.t0 tag = f"P{pid}" if t == 'log': print(f" [{tag}] {p['m']}") elif t == 'ready': self.ready_count += 1 elif t == 'file': fl = ' '.join(f'[{f}]' for f in p.get('fl',[])) m = 'W' if p.get('w') else 'R'; c = '+C' if p.get('c') else '' print(f" [{ts:7.2f}s] [{tag}] [FILE {m}{c}] {p['path']} {fl}") self.ev.append({**p, 'pid': pid}) elif t == 'move': print(f" [{ts:7.2f}s] [{tag}] [MOVE] {p['src']} -> {p['dst']}") self.ev.append({**p, 'pid': pid}) elif t == 'copy': print(f" [{ts:7.2f}s] [{tag}] [COPY] {p['src']} -> {p['dst']}") self.ev.append({**p, 'pid': pid}) elif t == 'mkdir': print(f" [{ts:7.2f}s] [{tag}] [MKDIR] {p['path']}") self.ev.append({**p, 'pid': pid}) elif t == 'write': tg = ', '.join(p.get('tags',[])) if tg: print(f" [{ts:7.2f}s] [{tag}] [WRITE] {p['sz']}b {tg}") self.ev.append({**p, 'pid': pid}) elif t == 'bmp': print(f" [{ts:7.2f}s] [{tag}] [BITMAP] {p['op']} {p['w']}x{p['h']} @{p['bpp']}bpp ({p['alloc']:,.0f}b)") self.ev.append({**p, 'pid': pid}) elif t == 'clip': print(f" [{ts:7.2f}s] [{tag}] [CLIP] {p['op']} {p['name']}") self.ev.append({**p, 'pid': pid}) elif t == 'net': print(f" [{ts:7.2f}s] [{tag}] [NET] {p['d']} {p['sz']}b #{p['n']}") self.ev.append({**p, 'pid': pid}) elif t == 'alert': print(f"\n {'!'*50}\n [{tag}] ALERT: {p['m']}\n {'!'*50}\n") self.ev.append({**p, 'pid': pid}) elif t == 'stats': total = p['s'] + p['r'] + p.get('ws',0) + p.get('wr',0) if total > 0: # Only print stats if there's activity print(f" [{ts:7.2f}s] [{tag}] send={p['s']} recv={p['r']} WSASend={p.get('ws',0)} WSARecv={p.get('wr',0)}") elif msg['type'] == 'error': print(f" [P{pid}] ERROR: {msg['description']}") def save(self): path = os.path.join(self.d, "capture.json") with open(path, 'w') as f: json.dump({'dur': time.time()-self.t0, 'events': self.ev}, f, indent=2) fi = [e for e in self.ev if e.get('t')=='file'] bm = [e for e in self.ev if e.get('t')=='bmp'] cl = [e for e in self.ev if e.get('t')=='clip'] nt = [e for e in self.ev if e.get('t')=='net'] al = [e for e in self.ev if e.get('t')=='alert'] print(f"\n[+] {len(self.ev)} events -> {path}") print(f" Files:{len(fi)} Bitmaps:{len(bm)} Clip:{len(cl)} Net:{len(nt)} Alerts:{len(al)}") def find_all_pids(): out = subprocess.check_output( ['tasklist', '/FI', 'IMAGENAME eq AnyDesk.exe', '/FO', 'CSV', '/NH'], text=True, stderr=subprocess.DEVNULL) pids = [] for line in out.strip().split('\n'): if 'AnyDesk' in line: parts = line.strip().strip('"').split('","') if len(parts) >= 2: pids.append(int(parts[1].strip('"'))) return pids def main(): print("=" * 60) print(" AnyDesk Sniffer v4 — ALL processes") print("=" * 60) pids = find_all_pids() if not pids: print("[!] No AnyDesk processes found") sys.exit(1) print(f"[+] Found {len(pids)} AnyDesk processes: {pids}") ts = datetime.now().strftime('%Y%m%d_%H%M%S') cap = Capture(os.path.join(CAPTURE_DIR, f"cap_{ts}")) sessions = [] scripts = [] for pid in pids: try: print(f"[+] Attaching to PID {pid}...") session = frida.attach(pid) script = session.create_script(AGENT_CODE, runtime='v8') script.on('message', lambda msg, data, p=pid: cap.on_msg(p, msg, data)) script.load() sessions.append(session) scripts.append(script) print(f"[+] PID {pid} hooked") except Exception as e: print(f"[!] PID {pid} failed: {e}") # Wait for all to be ready for _ in range(100): if cap.ready_count >= len(scripts): break time.sleep(0.1) print(f"\n{'='*60}") print(f" {cap.ready_count}/{len(scripts)} agents ready") print(" NOW: connect from VM, transfer files, move mouse") print(" Ctrl+C to stop") print(f"{'='*60}\n") try: while True: time.sleep(0.1) except KeyboardInterrupt: print("\n[+] Stopping...") cap.save() for s in sessions: try: s.detach() except: pass if __name__ == '__main__': main()