0

I have a program (ELF, 32 bits) that is probably quite short and simple, but which have been obfuscated with the following construction:

i = 0
switch(i):
    case 0:
        one small instruction
        i = 1
    case 1:
        one small instruction
        i = 2
    case 2:
        ....

An example of assembly would be:

loc_804E5E8:                                                             
                pop     eax             
                push    eax
                mov     eax, 20h
                push    eax
                mov     eax, 4B3h
                jmp     loc_804FE24

where loc_804FE24 contains the loading of the offset from the table, and the jmp eax.

There are some minor differences sometimes, it is not always perfectly linear like this, but it mostly follow this schema. How should I approach the reversing of this program? I'm pretty sure there is a simple and basic way to handle this, but I am pretty new to the field of reverse engineering. Thank you.

EDIT : if there is a way to recover all the instructions that are effectively executed one after the another, maybe writing a parser would be efficient ?

EDIT2 : I wondered if using a symbolic execution engine would be appropriate or not. Based on this link, symbolic execution is best used when:

  • there is no branches, no loops,
  • the instruction aren't playing with the EFLAGS register.
  • the instruction only used 32 bits registers (not 16 bits, or 8 bits).
  • the number of unique instruction is really small (i.e. only mov, shr, shl, xor, and, xor, add)
  • the instructions used are easy to emulate.

though in my case, there are a couple branches, some EFLAGS uses with pushf / popf, and some low sized registers. But if this approach really isn't pertinent here, I really am at a loss for ideas.

3
  • Can you attach the ELF as well?
    – sudhackar
    Jan 31 at 6:54
  • Sorry, I can't.
    – Katoptriss
    Jan 31 at 9:47
  • This technique is called "control-flow flattening"! People have dealt with it in all kinds of ways and the term itself should lead you to further reading but I'm not aware of a finished applicable solution. You'll probably have to tailor something to your exact use case. Feb 5 at 18:45

2 Answers 2

1

if there is a way to recover all the instructions that are effectively executed one after the another

do you mean you need to automatically single step each instruction and log the results including registers ?

if that is what you are looking for then some emulators like unicorn or unicorn based Qiling should be able to do that have you checked them out ?

here is a small src and emulation of a windows executable

source

:\>cat mcall.cpp
int foo(int a, int b, int c);
int main(void)
{
    int p = foo(1, 2, 3);
    int q = foo(8, 7, 6);
    int r = foo(3, 4, 5);
    int s = foo(1, 1, 5);
    int t = foo(8, 8, 5);
    int u = foo(5, 5, 5);
    return foo(p, q, r) * foo(s, t, u);
}
int foo(int a, int b, int c)
{
    return a + b + c;
}
:\>

compiled as x64 under win 10 using vs community dev prompt
most of the arguments are not required
unless you are trying to build a teensy executable with just one section and one header with no crt or no imports and no debug info

:\>cat complink.bat
cl /W4 /analyze:autolog- /Gs- /Od %1.cpp /link /release /FIXED /ENTRY:main /SUBSYSTEM:WINDOWS /DYNAMICBASE:NO /MERGE:.rdata=.text /MERGE:.pdata=.text
:\>

compiled executable details

:\>file mcall.exe
mcall.exe: PE32+ executable (GUI) x86-64, for MS Windows

:\>ls -lg mcall.exe
-rwxr-xr-x 1 197121 1536 Feb  3 18:51 mcall.exe

using Qiling to emulate from start to end

:\>cat qilthis.py
import os
import sys
from qiling import *
from qiling.const import QL_VERBOSE
from qiling.extensions import trace
os.system('')
rootfs = r"F:\QILING\examples\rootfs\x8664_windows"
ql = Qiling([sys.argv[1]],rootfs,verbose=QL_VERBOSE.DEBUG,stop_on_exit_trap=True)
trace.enable_full_trace(ql)
ql.run()
:\>

traced the main() and sub-function foo(x,y,z) and logged results.

:\>python qilthis.py mcall.exe
[+] Profile: Default
[+] Windows Registry PATH: F:\QILING\examples\rootfs\x8664_windows\Windows\registry
[=] Initiate stack address at 0x7ffffffde000
[=] Loading mcall.exe to 0x140000000
[=] PE entry point at 0x1400010e0
[=] TEB addr is 0x6000030
[=] PEB addr is 0x60000b8
[=] Loading F:\QILING\examples\rootfs\x8664_windows\Windows\System32\ntdll.dll ...
[!] Warnings while loading F:\QILING\examples\rootfs\x8664_windows\Windows\System32\ntdll.dll:
[!]  - SizeOfHeaders is smaller than AddressOfEntryPoint: this file cannot run under Windows 8.
[!]  - AddressOfEntryPoint lies outside the sections' boundaries. AddressOfEntryPoint: 0x0
[+] DLL preferred base address: 0x180000000
[=] Done with loading F:\QILING\examples\rootfs\x8664_windows\Windows\System32\ntdll.dll
[=] Loading F:\QILING\examples\rootfs\x8664_windows\Windows\System32\kernel32.dll ...
[+] DLL preferred base address: 0x180000000
[+] DLL preferred base address is taken, loading to: 0x1801f0000
[=] Done with loading F:\QILING\examples\rootfs\x8664_windows\Windows\System32\kernel32.dll
[+] Done with loading mcall.exe
[+] Setting up exit trap at 0x0x140002000
[+] 1400010e0 | b848000000         mov        eax, 0x48               |
[+] 1400010e5 | e8e6000000         call       0x1400011d0             | rsp = 0x0, rip = 0x0
[+] 1400011d0 | 4883ec10           sub        rsp, 0x10               | rsp = 0x0
[+] 1400011d4 | 4c891424           mov        qword ptr [0x0], r10    | rsp = 0x0, r10 = 0x0
[+] 1400011d8 | 4c895c2408         mov        qword ptr [0x8], r11    | rsp = 0x0, r11 = 0x0
[+] 1400011dd | 4d33db             xor        r11, r11                | r11 = 0x0
[+] 1400011e0 | 4c8d542418         lea        r10, [0x18]             | rsp = 0x0
[+] 1400011e5 | 4c2bd0             sub        r10, rax                | r10 = 0x0, rax = 0x80000001d000
[+] 1400011e8 | 4d0f42d3           cmovb      r10, r11                | rflags = 0x14, r10 = 0x0, r11 = 0x0
[+] 1400011ec | 654c8b1c2510000000 mov        r11, qword ptr [0x10]   | gs = 0x11ec
[+] 1400011f5 | 4d3bd3             cmp        r10, r11                | r10 = 0x0, r11 = 0x0
[+] 1400011f8 | f27317             bnd jae    0x140001212             | rflags = 0x4
[+] 140001212 | 4c8b1424           mov        r10, qword ptr [0x0]    | rsp = 0x0
[+] 140001216 | 4c8b5c2408         mov        r11, qword ptr [0x8]    | rsp = 0x0
[+] 14000121b | 4883c410           add        rsp, 0x10               | rsp = 0x0
[+] 14000121f | f2c3               bnd ret                            | rsp = 0x0
[+] 1400010ea | 482be0             sub        rsp, rax                | rsp = 0x0, rax = 0x80000001d000
[+] 1400010ed | 41b803000000       mov        r8d, 0x3                |
[+] 1400010f3 | ba02000000         mov        edx, 0x2                |
[+] 1400010f8 | b901000000         mov        ecx, 0x1                |
[+] 1400010fd | e8aeffffff         call       0x1400010b0             | rsp = 0x0, rip = 0x0
[+] 1400010b0 | 4489442418         mov        dword ptr [0x18], r8d   | rsp = 0x0, r8d = 0x0
[+] 1400010b5 | 89542410           mov        dword ptr [0x10], edx   | rsp = 0x0, edx = 0x2
[+] 1400010b9 | 894c2408           mov        dword ptr [0x8], ecx    | rsp = 0x0, ecx = 0x1
[+] 1400010bd | 8b442410           mov        eax, dword ptr [0x10]   | rsp = 0x0
[+] 1400010c1 | 8b4c2408           mov        ecx, dword ptr [0x8]    | rsp = 0x0
[+] 1400010c5 | 03c8               add        ecx, eax                | ecx = 0x1, eax = 0x2
[+] 1400010c7 | 8bc1               mov        eax, ecx                | ecx = 0x3
[+] 1400010c9 | 03442418           add        eax, dword ptr [0x18]   | eax = 0x3, rsp = 0x0
[+] 1400010cd | c3                 ret                                | rsp = 0x0
[+] 140001102 | 89442428           mov        dword ptr [0x28], eax   | rsp = 0x0, eax = 0x6
[+] 140001106 | 41b806000000       mov        r8d, 0x6                |
[+] 14000110c | ba07000000         mov        edx, 0x7                |
[+] 140001111 | b908000000         mov        ecx, 0x8                |
[+] 140001116 | e895ffffff         call       0x1400010b0             | rsp = 0x0, rip = 0x0
[+] 1400010b0 | 4489442418         mov        dword ptr [0x18], r8d   | rsp = 0x0, r8d = 0x0
[+] 1400010b5 | 89542410           mov        dword ptr [0x10], edx   | rsp = 0x0, edx = 0x7
[+] 1400010b9 | 894c2408           mov        dword ptr [0x8], ecx    | rsp = 0x0, ecx = 0x8
[+] 1400010bd | 8b442410           mov        eax, dword ptr [0x10]   | rsp = 0x0
[+] 1400010c1 | 8b4c2408           mov        ecx, dword ptr [0x8]    | rsp = 0x0
[+] 1400010c5 | 03c8               add        ecx, eax                | ecx = 0x8, eax = 0x7
[+] 1400010c7 | 8bc1               mov        eax, ecx                | ecx = 0xf
[+] 1400010c9 | 03442418           add        eax, dword ptr [0x18]   | eax = 0xf, rsp = 0x0
[+] 1400010cd | c3                 ret                                | rsp = 0x0
[+] 14000111b | 89442424           mov        dword ptr [0x24], eax   | rsp = 0x0, eax = 0x15
[+] 14000111f | 41b805000000       mov        r8d, 0x5                |
[+] 140001125 | ba04000000         mov        edx, 0x4                |
[+] 14000112a | b903000000         mov        ecx, 0x3                |
[+] 14000112f | e87cffffff         call       0x1400010b0             | rsp = 0x0, rip = 0x0
[+] 1400010b0 | 4489442418         mov        dword ptr [0x18], r8d   | rsp = 0x0, r8d = 0x0
[+] 1400010b5 | 89542410           mov        dword ptr [0x10], edx   | rsp = 0x0, edx = 0x4
[+] 1400010b9 | 894c2408           mov        dword ptr [0x8], ecx    | rsp = 0x0, ecx = 0x3
[+] 1400010bd | 8b442410           mov        eax, dword ptr [0x10]   | rsp = 0x0
[+] 1400010c1 | 8b4c2408           mov        ecx, dword ptr [0x8]    | rsp = 0x0
[+] 1400010c5 | 03c8               add        ecx, eax                | ecx = 0x3, eax = 0x4
[+] 1400010c7 | 8bc1               mov        eax, ecx                | ecx = 0x7
[+] 1400010c9 | 03442418           add        eax, dword ptr [0x18]   | eax = 0x7, rsp = 0x0
[+] 1400010cd | c3                 ret                                | rsp = 0x0
[+] 140001134 | 89442420           mov        dword ptr [0x20], eax   | rsp = 0x0, eax = 0xc
[+] 140001138 | 41b805000000       mov        r8d, 0x5                |
[+] 14000113e | ba01000000         mov        edx, 0x1                |
[+] 140001143 | b901000000         mov        ecx, 0x1                |
[+] 140001148 | e863ffffff         call       0x1400010b0             | rsp = 0x0, rip = 0x0
[+] 1400010b0 | 4489442418         mov        dword ptr [0x18], r8d   | rsp = 0x0, r8d = 0x0
[+] 1400010b5 | 89542410           mov        dword ptr [0x10], edx   | rsp = 0x0, edx = 0x1
[+] 1400010b9 | 894c2408           mov        dword ptr [0x8], ecx    | rsp = 0x0, ecx = 0x1
[+] 1400010bd | 8b442410           mov        eax, dword ptr [0x10]   | rsp = 0x0
[+] 1400010c1 | 8b4c2408           mov        ecx, dword ptr [0x8]    | rsp = 0x0
[+] 1400010c5 | 03c8               add        ecx, eax                | ecx = 0x1, eax = 0x1
[+] 1400010c7 | 8bc1               mov        eax, ecx                | ecx = 0x2
[+] 1400010c9 | 03442418           add        eax, dword ptr [0x18]   | eax = 0x2, rsp = 0x0
[+] 1400010cd | c3                 ret                                | rsp = 0x0
[+] 14000114d | 89442434           mov        dword ptr [0x34], eax   | rsp = 0x0, eax = 0x7
[+] 140001151 | 41b805000000       mov        r8d, 0x5                |
[+] 140001157 | ba08000000         mov        edx, 0x8                |
[+] 14000115c | b908000000         mov        ecx, 0x8                |
[+] 140001161 | e84affffff         call       0x1400010b0             | rsp = 0x0, rip = 0x0
[+] 1400010b0 | 4489442418         mov        dword ptr [0x18], r8d   | rsp = 0x0, r8d = 0x0
[+] 1400010b5 | 89542410           mov        dword ptr [0x10], edx   | rsp = 0x0, edx = 0x8
[+] 1400010b9 | 894c2408           mov        dword ptr [0x8], ecx    | rsp = 0x0, ecx = 0x8
[+] 1400010bd | 8b442410           mov        eax, dword ptr [0x10]   | rsp = 0x0
[+] 1400010c1 | 8b4c2408           mov        ecx, dword ptr [0x8]    | rsp = 0x0
[+] 1400010c5 | 03c8               add        ecx, eax                | ecx = 0x8, eax = 0x8
[+] 1400010c7 | 8bc1               mov        eax, ecx                | ecx = 0x10
[+] 1400010c9 | 03442418           add        eax, dword ptr [0x18]   | eax = 0x10, rsp = 0x0
[+] 1400010cd | c3                 ret                                | rsp = 0x0
[+] 140001166 | 89442430           mov        dword ptr [0x30], eax   | rsp = 0x0, eax = 0x15
[+] 14000116a | 41b805000000       mov        r8d, 0x5                |
[+] 140001170 | ba05000000         mov        edx, 0x5                |
[+] 140001175 | b905000000         mov        ecx, 0x5                |
[+] 14000117a | e831ffffff         call       0x1400010b0             | rsp = 0x0, rip = 0x0
[+] 1400010b0 | 4489442418         mov        dword ptr [0x18], r8d   | rsp = 0x0, r8d = 0x0
[+] 1400010b5 | 89542410           mov        dword ptr [0x10], edx   | rsp = 0x0, edx = 0x5
[+] 1400010b9 | 894c2408           mov        dword ptr [0x8], ecx    | rsp = 0x0, ecx = 0x5
[+] 1400010bd | 8b442410           mov        eax, dword ptr [0x10]   | rsp = 0x0
[+] 1400010c1 | 8b4c2408           mov        ecx, dword ptr [0x8]    | rsp = 0x0
[+] 1400010c5 | 03c8               add        ecx, eax                | ecx = 0x5, eax = 0x5
[+] 1400010c7 | 8bc1               mov        eax, ecx                | ecx = 0xa
[+] 1400010c9 | 03442418           add        eax, dword ptr [0x18]   | eax = 0xa, rsp = 0x0
[+] 1400010cd | c3                 ret                                | rsp = 0x0
[+] 14000117f | 8944242c           mov        dword ptr [0x2c], eax   | rsp = 0x0, eax = 0xf
[+] 140001183 | 448b442420         mov        r8d, dword ptr [0x20]   | rsp = 0x0
[+] 140001188 | 8b542424           mov        edx, dword ptr [0x24]   | rsp = 0x0
[+] 14000118c | 8b4c2428           mov        ecx, dword ptr [0x28]   | rsp = 0x0
[+] 140001190 | e81bffffff         call       0x1400010b0             | rsp = 0x0, rip = 0x0
[+] 1400010b0 | 4489442418         mov        dword ptr [0x18], r8d   | rsp = 0x0, r8d = 0x0
[+] 1400010b5 | 89542410           mov        dword ptr [0x10], edx   | rsp = 0x0, edx = 0x15
[+] 1400010b9 | 894c2408           mov        dword ptr [0x8], ecx    | rsp = 0x0, ecx = 0x6
[+] 1400010bd | 8b442410           mov        eax, dword ptr [0x10]   | rsp = 0x0
[+] 1400010c1 | 8b4c2408           mov        ecx, dword ptr [0x8]    | rsp = 0x0
[+] 1400010c5 | 03c8               add        ecx, eax                | ecx = 0x6, eax = 0x15
[+] 1400010c7 | 8bc1               mov        eax, ecx                | ecx = 0x1b
[+] 1400010c9 | 03442418           add        eax, dword ptr [0x18]   | eax = 0x1b, rsp = 0x0
[+] 1400010cd | c3                 ret                                | rsp = 0x0
[+] 140001195 | 89442438           mov        dword ptr [0x38], eax   | rsp = 0x0, eax = 0x27
[+] 140001199 | 448b44242c         mov        r8d, dword ptr [0x2c]   | rsp = 0x0
[+] 14000119e | 8b542430           mov        edx, dword ptr [0x30]   | rsp = 0x0
[+] 1400011a2 | 8b4c2434           mov        ecx, dword ptr [0x34]   | rsp = 0x0
[+] 1400011a6 | e805ffffff         call       0x1400010b0             | rsp = 0x0, rip = 0x0
[+] 1400010b0 | 4489442418         mov        dword ptr [0x18], r8d   | rsp = 0x0, r8d = 0x0
[+] 1400010b5 | 89542410           mov        dword ptr [0x10], edx   | rsp = 0x0, edx = 0x15
[+] 1400010b9 | 894c2408           mov        dword ptr [0x8], ecx    | rsp = 0x0, ecx = 0x7
[+] 1400010bd | 8b442410           mov        eax, dword ptr [0x10]   | rsp = 0x0
[+] 1400010c1 | 8b4c2408           mov        ecx, dword ptr [0x8]    | rsp = 0x0
[+] 1400010c5 | 03c8               add        ecx, eax                | ecx = 0x7, eax = 0x15
[+] 1400010c7 | 8bc1               mov        eax, ecx                | ecx = 0x1c
[+] 1400010c9 | 03442418           add        eax, dword ptr [0x18]   | eax = 0x1c, rsp = 0x0
[+] 1400010cd | c3                 ret                                | rsp = 0x0
[+] 1400011ab | 8b4c2438           mov        ecx, dword ptr [0x38]   | rsp = 0x0
[+] 1400011af | 0fafc8             imul       ecx, eax                | ecx = 0x27, eax = 0x2b
[+] 1400011b2 | 8bc1               mov        eax, ecx                | ecx = 0x68d
[+] 1400011b4 | 4883c448           add        rsp, 0x48               | rsp = 0x0
[+] 1400011b8 | c3                 ret                                | rsp = 0x0
[+] 140002000 | 90                 nop                                |
[=] Process returned from entrypoint (exit_trap)!
[+] Syscalls called:
[+] Registries accessed:
[+] Strings:

:\>
1
  • Thank you very much for suggesting Qiling, I didn't know about this framework and the fact that the values of the registers are available in the tracing log is extremely useful.
    – Katoptriss
    Feb 5 at 19:10
0

You could, like you mentioned, write a parser that removes jumps by glueing the code at the target address where the jump was. Just be careful to take note of the jump targets already encountered before, as to not get an infinite loop by accident.

You could also view it with the satelite view in Ghidra or IDA to figure out if somewhere in there is a bigger block which executes some code that they tried to hide with this tactic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.