Skip to content

Commit e95a73d

Browse files
authored
Merge pull request #1098 from HackTricks-wiki/update_Evolving_Tactics_of_SLOW_TEMPEST__A_Deep_Dive_Into_20250711_124156
Evolving Tactics of SLOW#TEMPEST A Deep Dive Into Advanced M...
2 parents d024864 + 6435c95 commit e95a73d

1 file changed

Lines changed: 92 additions & 1 deletion

File tree

src/generic-methodologies-and-resources/basic-forensic-methodology/malware-analysis.md

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,98 @@ If the files of a folder **shouldn't have been modified**, you can calculate the
169169

170170
When the information is saved in logs you can **check statistics like how many times each file of a web server was accessed as a web shell might be one of the most**.
171171

172-
{{#include ../../banners/hacktricks-training.md}}
172+
---
173+
174+
## Deobfuscating Dynamic Control-Flow (JMP/CALL RAX Dispatchers)
175+
176+
Modern malware families heavily abuse Control-Flow Graph (CFG) obfuscation: instead of a direct jump/call they compute the destination at run-time and execute a `jmp rax` or `call rax`. A small *dispatcher* (typically nine instructions) sets the final target depending on the CPU `ZF`/`CF` flags, completely breaking static CFG recovery.
177+
178+
The technique – showcased by the SLOW#TEMPEST loader – can be defeated with a three-step workflow that only relies on IDAPython and the Unicorn CPU emulator.
179+
180+
### 1. Locate every indirect jump / call
181+
182+
```python
183+
import idautils, idc
184+
185+
for ea in idautils.FunctionItems(idc.here()):
186+
mnem = idc.print_insn_mnem(ea)
187+
if mnem in ("jmp", "call") and idc.print_operand(ea, 0) == "rax":
188+
print(f"[+] Dispatcher found @ {ea:X}")
189+
```
190+
191+
### 2. Extract the dispatcher byte-code
192+
193+
```python
194+
import idc
195+
196+
def get_dispatcher_start(jmp_ea, count=9):
197+
s = jmp_ea
198+
for _ in range(count):
199+
s = idc.prev_head(s, 0)
200+
return s
201+
202+
start = get_dispatcher_start(jmp_ea)
203+
size = jmp_ea + idc.get_item_size(jmp_ea) - start
204+
code = idc.get_bytes(start, size)
205+
open(f"{start:X}.bin", "wb").write(code)
206+
```
207+
208+
### 3. Emulate it twice with Unicorn
209+
210+
```python
211+
from unicorn import *
212+
from unicorn.x86_const import *
213+
import struct
214+
215+
def run(code, zf=0, cf=0):
216+
BASE = 0x1000
217+
mu = Uc(UC_ARCH_X86, UC_MODE_64)
218+
mu.mem_map(BASE, 0x1000)
219+
mu.mem_write(BASE, code)
220+
mu.reg_write(UC_X86_REG_RFLAGS, (zf << 6) | cf)
221+
mu.reg_write(UC_X86_REG_RAX, 0)
222+
mu.emu_start(BASE, BASE+len(code))
223+
return mu.reg_read(UC_X86_REG_RAX)
224+
```
225+
226+
Run `run(code,0,0)` and `run(code,1,1)` to obtain the *false* and *true* branch targets.
227+
228+
### 4. Patch back a direct jump / call
229+
230+
```python
231+
import struct, ida_bytes
232+
233+
def patch_direct(ea, target, is_call=False):
234+
op = 0xE8 if is_call else 0xE9 # CALL rel32 or JMP rel32
235+
disp = target - (ea + 5) & 0xFFFFFFFF
236+
ida_bytes.patch_bytes(ea, bytes([op]) + struct.pack('<I', disp))
237+
```
238+
239+
After patching, force IDA to re-analyse the function so the full CFG and Hex-Rays output are restored:
240+
241+
```python
242+
import ida_auto, idaapi
243+
idaapi.reanalyze_function(idc.get_func_attr(ea, idc.FUNCATTR_START))
244+
```
245+
246+
### 5. Label indirect API calls
247+
248+
Once the real destination of every `call rax` is known you can tell IDA what it is so parameter types & variable names are recovered automatically:
249+
250+
```python
251+
idc.set_callee_name(call_ea, resolved_addr, 0) # IDA 8.3+
252+
```
253+
254+
### Practical benefits
255+
256+
* Restores the real CFG → decompilation goes from *10* lines to thousands.
257+
* Enables string-cross-reference & xrefs, making behaviour reconstruction trivial.
258+
* Scripts are reusable: drop them into any loader protected by the same trick.
259+
260+
---
173261

262+
## References
174263

264+
- [Unit42 – Evolving Tactics of SLOW#TEMPEST: A Deep Dive Into Advanced Malware Techniques](https://unit42.paloaltonetworks.com/slow-tempest-malware-obfuscation/)
175265

266+
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)