Check this exe perform reverse engineering and fin...
創建於:2026年9月30日
使用 GPT-5.6 Thinking 回答 Chat01
創建於:2026年9月30日
使用 GPT-5.6 Thinking 回答 Chat01
Check this exe perform reverse engineering and find if anything malicious c2 server IP address any malware code cause my one friend whatsapp account got compromise
I’ll treat the EXE as potentially hostile and do static analysis only—no execution. I’ll inspect its hashes, PE structure, imports, embedded strings/config, URLs/IPs/domains, persistence/stealer indicators, and any likely C2 artifacts, then summarize the risk and what to block.
The file is a 64-bit Windows GUI executable, 137,728 bytes, and it is not digitally signed (no PE security directory). Its PE timestamp is September 30, 2026 03:47:38 UTC, only hours before this analysis, which is notable for a file presented as an “E-Statement.” I’m now checking whether networking and credential-stealing behavior is hidden behind dynamically resolved APIs.
A stronger indicator has appeared: the executable contains the ChaCha/Salsa-family constant “expand 32-byte k”, suggesting encrypted embedded data or configuration. It also has almost no normal networking imports, so any C2 address may be decrypted only at runtime; I’m tracing the crypto/config code and dynamically resolved APIs rather than assuming “no URL in strings” means safe.
pythonimport math, struct, os, collections, json, re, hashlib, pathlib, statistics p="/mnt/data/September E-Statement.exe" data=open(p,'rb').read() len(data), hashlib.sha256(data).hexdigest() (137728, '9ec9474a49457c5d0a68c1133933a35dd81ad70193985723ef03f7740a9c6213')
python# basic PE parsing e_lfanew=struct.unpack_from("<I",data,0x3c)[0] sig=data[e_lfanew:e_lfanew+4] machine,nsects,timestamp,ptrsym,nsym,sizeopt,chars=struct.unpack_from("<HHIIIHH",data,e_lfanew+4) opt_off=e_lfanew+24 magic=struct.unpack_from("<H",data,opt_off)[0] imagebase=struct.unpack_from("<Q",data,opt_off+24)[0] sect_off=opt_off+sizeopt sects=[] for i in range(nsects): off=sect_off+i*40 name=data[off:off+8].rstrip(b"\0").decode(errors="replace") vsize,vaddr,rsize,roff=struct.unpack_from("<IIII",data,off+8) chunk=data[roff:roff+rsize] cnt=collections.Counter(chunk) ent= -sum((c/len(chunk))*math.log2(c/len(chunk)) for c in cnt.values()) if chunk else 0 sects.append((name,vsize,vaddr,rsize,roff,ent)) sects [('.text', 88710, 4096, 89088, 1024, 6.20772356686411), ('.rdata', 41772, 94208, 41984, 90112, 5.365427254068568), ('.data', 3075, 139264, 2048, 132096, 5.4533972599504645), ('.pdata', 2388, 143360, 2560, 134144, 4.786323452577038), ('.tls', 24, 147456, 512, 136704, -0.0), ('.reloc', 176, 151552, 512, 137216, 2.1991374007269457)]
pythonbase=0x140000000 data_rva=0x22000 data_off=0x20400 def va_to_off(va): rva=va-base for name,vsize,vaddr,rsize,roff,ent in sects: if vaddr <= rva < vaddr+rsize: return roff + (rva-vaddr) raise ValueError(hex(va)) def dec_blob(src_va,keylen,outlen): off=va_to_off(src_va) key=data[off:off+keylen] ct=data[off+keylen:off+keylen+outlen] out=bytearray() prev=0 for i,c in enumerate(ct): k=key[i%keylen] x=c if ((i%keylen)*k)&1==0: x=(x+prev)&0xff x ^= k x=(~x)&0xff else: x=(x-prev)&0xff x ^= k x=(-x)&0xff prev=x ^ k out.append(prev) return bytes(out),key,ct for args in [(0x140022173,0x1f,0x14),(0x140022173,0x1f,0x14)]: print(args, dec_blob(*args)[0])
pythonfrom pathlib import Path lines=Path('/mnt/data/exe_analysis/full_disasm.txt').read_text(errors='ignore').splitlines() call_indices=[i for i,l in enumerate(lines) if 'call' in l and '0x14001655d' in l] pat_rdx=re.compile(r'lea\s+rdx,$$rip[^$$]*\].*#\s*(0x[0-9a-fA-F]+)') pat_r8=re.compile(r'mov\s+r8d,(0x[0-9a-fA-F]+)') pat_r9=re.compile(r'mov\s+r9d,(0x[0-9a-fA-F]+)') rows=[] for n,i in enumerate(call_indices,1): src=klen=olen=None for j in range(i-1,max(-1,i-25),-1): l=lines[j] if src is None: m=pat_rdx.search(l) if m: src=int(m.group(1),16) if klen is None: m=pat_r8.search(l) if m: klen=int(m.group(1),16) if olen is None: m=pat_r9.search(l) if m: olen=int(m.group(1),16) if src is not None and klen is not None and olen is not None: break dec=None if src and klen and olen: try: dec=dec_blob(src,klen,olen)[0] except Exception as e: dec=repr(e).encode() rows.append((n,lines[i].strip().split(':')[0],hex(src) if src else None,klen,olen,dec)) rows [(1, '1400065b3', '0x14002220e', 17, 16, b'\xb2\x08\xbd\xbf\xe5$\x87R\xdf\x8d9MS\xd8\xcc\x00'), (2, '1400089f7', '0x1400220c5', 16, 16, b'src\\msvc_gpu.rs\x00'), (3, '140008aca', '0x1400220c5', 16, 16, b'src\\msvc_gpu.rs\x00'), (4, '14000a7b2', '0x14002213d', 19, 15, b'src\\uac\\rpc.rs\x00'), (5, '14000b238', '0x1400221bf', 27, 22, b'src\\crypto\\huffman.rs\x00'), (6, '14000b63e', '0x1400221bf', 27, 22, b'src\\crypto\\huffman.rs\x00'), (7, '14000b6bf', '0x1400221bf', 27, 22, b'src\\crypto\\huffman.rs\x00'), (8, '14000b95b', '0x140022173', 31, 20, b'src\\crypto\\lznt1.rs\x00'), (9, '14000b9a9', '0x140022173', 31, 20, b'src\\crypto\\lznt1.rs\x00'), (10, '14000bdea', None, 31, 20, None), (11, '14000bf55', '0x140022173', 31, 20, b'src\\crypto\\lznt1.rs\x00'), (12, '14000c21d', '0x140022173', 31, 20, b'src\\crypto\\lznt1.rs\x00'), (13, '14000e444', '0x140022173', 31, 20, b'src\\crypto\\lznt1.rs\x00'), (14, '14000eaf6', '0x1400220fd', 17, 17, b'src\\obfaessse.rs\x00'), (15, '14000eb32', '0x1400220fd', 17, 17, b'src\\obfaessse.rs\x00'), (16, '14000f17e', '0x1400220fd', 17, 17, b'src\\obfaessse.rs\x00'), (17, '14000f1cd', '0x1400220fd', 17, 17, b'src\\obfaessse.rs\x00'), (18, '14001297e', '0x140022173', 31, 20, b'src\\crypto\\lznt1.rs\x00'), (19, '140014693', '0x140022173', 31, 20, b'src\\crypto\\lznt1.rs\x00'), (20, '140014754', '0x14002208b', 21, 15, b'src\\xbuffer.rs\x00'), (21, '140015c3e', '0x14002224b', 21, 32, b'\x1b\xb6\xf1\x16\xbe\x99g\x18\x8b{M\xd8\xa8\xa7\x0c\xc4\xe1S\xa0\x01\x9ean1\x07z\xe8UC\xf7\xff\x00')]
pythonimport struct, math, re, os, pathlib, collections, itertools, textwrap, json, hashlib buf=bytearray(data) def rol32(x,n): return ((x<<n)|(x>>(32-n))) & 0xffffffff def ror32(x,n): return ((x>>n)|(x<<(32-n))) & 0xffffffff def crypt_sel2(dat,key): # xor Speck64/128 CTR-like # key 16 bytes, 4 little endian words w=list(struct.unpack("<4I", key)) k=[w[0]] l=[w[1],w[2],w[3]] for i in range(26): new_l=(ror32(l[i],8)+k[i]) & 0xffffffff new_l ^= i new_k=rol32(k[i],3) ^ new_l l.append(new_l) k.append(new_k & 0xffffffff) assert len(k)==27 out=bytearray(dat) off=0; ctr=0 while off<len(out): x=ctr & 0xffffffff y=0 for rk in k: x=(ror32(x,8)+y)&0xffffffff x ^= rk y=rol32(y,3)^x y &= 0xffffffff ks=struct.pack("<II", x, y) # based on assembly? verify n=min(8,len(out)-off) for j in range(n): out[off+j]^=ks[j] off+=n; ctr+=1 return bytes(out) def crypt_sel0(dat,key): S=[0]*256 k0=key[0] a=key[0]^key[5]^key[10] d=key[15] c=(a^d)&0xff if a==d: c=0x5a S[0]=(k0^c)&0xff for i in range(1,256): S[i]=((c+i)&0xff) ^ key[i&0xf] j=0 # special i=0 then general j=(key[0]+S[0])&0xff S[0],S[j]=S[j],S[0] for i in range(1,256): j=(key[i&0xf]+S[i]+j)&0xff S[i],S[j]=S[j],S[i] # 256 warmup PRGA i=0; j=0 for _ in range(256): i=(i+1)&0xff j=(j+S[i])&0xff S[i],S[j]=S[j],S[i] # no output out=bytearray(dat) for p in range(len(out)): i=(i+1)&0xff j=(j+S[i])&0xff S[i],S[j]=S[j],S[i] K=S[(S[i]+S[j])&0xff] out[p]^=K return bytes(out) calls=[ (0x1400222f0,0x1f,1,0x00ceeb21003a21a5,0x00311b2a00b9c4f6), (0x14002230f,0x1c,0,0x00ffa73800d04f9c,0x00bb595f005ca39f), (0x140022330,0x20,0,0x00bebdd20074be3d,0x0025dee2001a75aa), (0x140022350,0x25,0,0x00494db6003e68d3,0x001fe41c00b8254e), (0x140022378,0x23,1,0x00e7029100aa3746,0x0048c122003d2800), (0x1400223a0,0x36,1,0x00e1d21500e0cab6,0x009978810083dad1), (0x1400223d6,0x0e,1,0x008b06c2006ef66f,0x00e33def000088f6), (0x1400223e8,0x2b,2,0x00c1251e00b8aa43,0x00ba18eb00db6157), (0x140022430,0x32,1,0x002b971800982d6f,0x0002a46c0016153f), (0x140022468,0x2a,2,0x007e305200c6974e,0x0035bb6d00fa8241), (0x140022498,0x53,2,0x007af96c009249d9,0x00f93d6000724018), (0x1400224f0,0x20,1,0x00c71376003545e2,0x000c4f3600a11fb8), (0x140022510,0x31,0,0x00bd8ad1006391b8,0x005da181009984b2), (0x140022548,0x27,0,0x0027526300d90c38,0x00ee992400c578d2), (0x14002256f,0x1c,2,0x00cb9d1d0054bb70,0x00d2ed6b001601f2), ] for va,n,sel,s1,s2 in calls: off=va_to_off(va) enc=data[off:off+n] key=struct.pack("<QQ",s1,s2) if sel==0: dec=crypt_sel0(enc,key) elif sel==2: dec=crypt_sel2(enc,key) else: dec=b"" print(hex(va),n,sel,dec)
The static decryption is working. I recovered hidden source-path strings including src\uac\rpc.rs, src\crypto\lznt1.rs, src\crypto\huffman.rs, src\msvc_gpu.rs, and src\obfaessse.rs. Those names point to custom UAC/obfuscation/compression code rather than a normal bank statement viewer; I’m separating compiler/runtime strings from the executable’s own payload and network logic now.
The hidden-string routine is AES-based, not a simple XOR wrapper. The executable builds AES key material at runtime and decrypts strings/blobs only when needed, which explains why normal string scanning does not reveal its API names or C2 configuration. I’m extracting those call-site keys and encrypted buffers directly from the PE rather than running the program.
I’ve now validated the decryptor against real embedded strings. For example, encrypted data decrypts to kernel32.dll, CreateFileW, DeviceIoControl, CloseHandle, GetDiskFreeSpaceExW, and a UTF-16 path to C:\Windows\System32\ntdll.dll. This confirms the reverse-engineering method is correct; I can now bulk-decrypt the rest of the hidden strings and look specifically for network/C2 and credential/session theft APIs.
My static reverse-engineering indicates high confidence this is a malicious loader / privilege-escalation / process-injection component, not a legitimate e-statement viewer.
| Finding | Result |
|---|---|
| Malicious behavior | Yes — high confidence |
| Hard-coded C2 IP/domain | None recovered statically |
| Process injection | Yes |
| UAC / privilege escalation | Yes |
| Anti-VM / anti-analysis | Yes |
| Security-event-log reconnaissance | Yes |
| Direct WhatsApp-stealer code | Not found |
| Encrypted/obfuscated strings | Yes — AES + other custom crypto |
| Digital signature | None |
Filename: September E-Statement.exe
Size: 137,728 bytes
Architecture: Windows x64 GUI executable
PE compile timestamp: September 30, 2026 03:47:38 UTC
SHA-256:
text9ec9474a49457c5d0a68c1133933a35dd81ad70193985723ef03f7740a9c6213
SHA-1:
textd951998e2f22019b961fd3c418da5827ff88bc4a
MD5:
texta13b02d5b774b18d3e56a8e12199c2a6
I also found no Authenticode signature.
I recovered 236 of 237 AES-protected strings/API references. Among them are APIs associated with remote-process manipulation and injection:
textNtOpenProcess NtAllocateVirtualMemory ZwAllocateVirtualMemory NtWriteVirtualMemory VirtualAllocEx WriteProcessMemory NtDuplicateObject DuplicateHandle NtQueryInformationProcess NtQuerySystemInformation PostQueuedCompletionStatus ZwSetIoCompletion
The combination of opening another process, allocating memory inside it, writing to that memory and manipulating handles is strongly consistent with an injection / process-migration loader.
It also contains privilege-manipulation functionality:
textOpenProcessToken LookupPrivilegeValueW AdjustTokenPrivileges SeDebugPrivilege GetTokenInformation CreateProcessAsUserW IsUserAnAdmin
More importantly, I recovered this RPC interface UUID:
text201ef99a-7fa0-444c-9399-19ba84f12a1a
That UUID belongs to the Windows AppInfo RPC interface used for UAC process elevation; Project Zero documents its RAiLaunchAdminProcess functionality. (googleprojectzero.blogspot.com)
The executable additionally contains strings/functions for:
textRpcAsyncInitializeHandle RpcBindingFromStringBindingW RpcBindingSetAuthInfoExW RpcStringBindingComposeW NdrAsyncClientCall RpcRaiseException winver.exe WinSta0\Default ncalrpc
There is public UAC-bypass tooling using this same AppInfo RPC interface together with debug-object manipulation; the public Elevator project is one example. That doesn't establish that this sample is Elevator, but the implementation technique is very similar. (GitHub)
I decrypted strings including:
textOpenSCManagerW EnumServicesStatusExW OpenServiceW StartServiceW QueryServiceStatus Schedule ROOT\CIMV2 WQL SELECT ProcessId FROM Win32_Service WHERE Name='
The code appears to locate/start a Windows service, obtain its process ID, and then pass that PID into code containing the process-memory/injection APIs above.
It specifically looks for virtualization/environment indicators including:
textvirtual vmware vbox hyper-v
and registry keys involving:
textSOFTWARE\Microsoft\Hyper-V ...\CurrentVersion\Virtualization ...\NET Framework Setup\NDP\v4\Full ...\PowerShell\3
It also queries memory, disk space and GPU functionality. That behavior is typical of malware deciding whether it is running inside an analysis sandbox.
The program dynamically resolves Windows Event Log APIs such as:
textEvtQuery EvtNext EvtRender EvtClose
and searches the Windows Security log for:
text*[System[EventID=1102]] *[System[EventID=4624]]
Event 1102 relates to the Security audit log being cleared, while 4624 represents successful logons. A fake e-statement application has no legitimate reason to perform this kind of host-security reconnaissance.
This is the important limitation: I did not recover a hard-coded C2 IP, domain, URL or HTTP endpoint from this EXE.
After decrypting essentially the whole protected-string table, I found none of the normal networking artifacts such as:
textWinHTTP WinINet InternetOpen HttpSendRequest WSAStartup socket connect getaddrinfo http:// https://
I also found no plaintext IP/domain configuration.
That does not mean it is harmless or that there is no C2. The behavior strongly suggests this EXE can act as an initial loader/elevation/injection stage. Its next-stage payload could be downloaded by another mechanism, embedded in an encrypted/compressed blob, injected into another process, or supplied externally. The actual C2 could therefore exist only in that second stage or memory.
I did not find direct WhatsApp-specific or browser-session-stealing strings such as WhatsApp, Chrome/Edge/Firefox profile paths, cookie databases, or CryptUnprotectData in the recovered string set. So this static analysis alone does not prove this EXE directly stole the WhatsApp account.
But if your friend executed this file, I would consider that Windows machine compromised. The executable has the building blocks to elevate privileges and inject another payload into other processes. A second-stage credential/session stealer could then compromise email, browsers, WhatsApp Web/Desktop sessions, or other accounts.
Do these from a known-clean phone or computer, not the suspected Windows machine:
The best way to get the actual C2 IP/domain now is to inspect telemetry from the computer around the time this file was executed: Sysmon/Windows EVTX logs, Microsoft Defender/EDR logs, DNS/firewall/router logs, or a memory dump. If you upload those, I can trace the second-stage execution and specifically hunt for the C2 connection.