Instruction camouflage is an obfuscation technique against simple naive static
analysis of the binary. The binary program is composed of two parts:
- A decoder
- An encoded payload
When executed, the binary first goes to the decoder and decode the
payload that unveil the real assembly code. At the end, the decoder
jumps to the decoded payload and execute the code.
The benefit of this technique is that statically disassembling the
binary will not give you hints on what is really doing the program.
Somehow, it forces the analyst to execute first the decoder part (for
real or symbolically) and, then, look at the decoded payload.
In the proposed example, the decoder part is the following:
0804840c <main>:
804840c: be 1e 84 04 08 mov $0x804841e,%esi
8048411: 89 f7 mov %esi,%edi
8048413: b9 26 00 00 00 mov $0x26,%ecx
8048418: ac lods %ds:(%esi),%al
8048419: 34 aa xor $0xaa,%al
804841b: aa stos %al,%es:(%edi)
804841c: e2 fa loop 8048418 <main+0xc>
You can see that there is a loop between 0x8048418
and 0x804841c
which apply a xor 0xaa
to each byte in the payload (from 0x804841e
to 0x804841e + 0x25 = 0x8048443
, the loop counter is %ecx
).
So, the best way to know what is done in the payload is to take gdb
and to set a breakpoint after the decoder has completed his task:
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
(gdb) break main
Breakpoint 1 at 0x804840c
(gdb) run
Starting program: ./instruction_camouflage
Breakpoint 1, 0x0804840c in main ()
Lets check that the code hasn't change.
(gdb) disas
Dump of assembler code for function main:
=> 0x0804840c <+0>: mov $0x804841e,%esi
0x08048411 <+5>: mov %esi,%edi
0x08048413 <+7>: mov $0x26,%ecx
0x08048418 <+12>: lods %ds:(%esi),%al
0x08048419 <+13>: xor $0xaa,%al
0x0804841b <+15>: stos %al,%es:(%edi)
0x0804841c <+16>: loop 0x8048418 <main+12>
0x0804841e <+18>: and 0x29(%edi),%ecx
0x08048421 <+21>: inc %esi
0x08048422 <+22>: scas %es:(%edi),%al
0x08048423 <+23>: sub %ecx,0x5a(%esi)
0x08048426 <+26>: sub %ebp,-0x52(%esi)
0x08048429 <+29>: ret $0x2e9c
0x0804842c <+32>: scas %es:(%edi),%al
0x0804842d <+33>: mov %al,0x55541742
0x08048432 <+38>: push %ebp
0x08048433 <+39>: and 0x69(%esi),%eax
0x08048436 <+42>: loop 0x8048407 <frame_dummy+39>
0x08048438 <+44>: mov $0xc5,%dh
0x0804843b <+47>: mov %ch,%bh
0x0804843d <+49>: vshufps $0x8b,%xmm6,%xmm4,%xmm1
0x08048442 <+54>: mov 0x909090aa,%al
0x08048447 <+59>: nop
...
0x0804844f <+67>: nop
End of assembler dump.
Let's put a breakpoint just after the loop and continue till it is reached.
(gdb) break *0x0804841e
Breakpoint 2 at 0x804841e
(gdb) continue
Continuing.
Breakpoint 2, 0x0804841e in main ()
Now, we should be able to access the code as it will be executed.
(gdb) disas
Dump of assembler code for function main:
0x0804840c <+0>: mov $0x804841e,%esi
0x08048411 <+5>: mov %esi,%edi
0x08048413 <+7>: mov $0x26,%ecx
0x08048418 <+12>: lods %ds:(%esi),%al
0x08048419 <+13>: xor $0xaa,%al
0x0804841b <+15>: stos %al,%es:(%edi)
0x0804841c <+16>: loop 0x8048418 <main+12>
=> 0x0804841e <+18>: and %ebp,%esp
0x08048420 <+20>: sub $0x4,%esp
0x08048423 <+23>: and $0xfffffff0,%esp
0x08048426 <+26>: add $0x4,%esp
0x08048429 <+29>: push $0x8048436
0x0804842e <+34>: call 0x80482f0 <puts@plt>
0x08048433 <+39>: mov %ebp,%esp
0x08048435 <+41>: ret
0x08048436 <+42>: dec %eax
0x08048437 <+43>: gs
0x08048438 <+44>: insb (%dx),%es:(%edi)
0x08048439 <+45>: insb (%dx),%es:(%edi)
0x0804843a <+46>: outsl %ds:(%esi),(%dx)
0x0804843b <+47>: and %dl,0x6f(%edi)
0x0804843e <+50>: jb 0x80484ac <__libc_csu_init+76>
0x08048440 <+52>: and %ecx,%fs:(%edx)
0x08048443 <+55>: add %dl,-0x6f6f6f70(%eax)
0x08048449 <+61>: nop
...
0x0804844f <+67>: nop
End of assembler dump.
And, still there is these strange instructions after the ret
, lets visualize it as a string.
(gdb) x /s 0x08048436
0x8048436 <main+42>: "Hello World!\n"
So, we found all the pieces of the program and how it works.