10

I have an obfuscated binary which only print a simple Hello World! and exit like this:

Hello World!

But, when I am looking at the assembly with objdump, I cannot find any call to printf or write, nor find the string Hello World!.

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>
 804841e:       23 4f 29                and    0x29(%edi),%ecx
 8048421:       46                      inc    %esi
 8048422:       ae                      scas   %es:(%edi),%al
 8048423:       29 4e 5a                sub    %ecx,0x5a(%esi)
 8048426:       29 6e ae                sub    %ebp,-0x52(%esi)
 8048429:       c2 9c 2e                ret    $0x2e9c
 804842c:       ae                      scas   %es:(%edi),%al
 804842d:       a2 42 17 54 55          mov    %al,0x55541742
 8048432:       55                      push   %ebp
 8048433:       23 46 69                and    0x69(%esi),%eax
 8048436:       e2 cf                   loop   8048407 <frame_dummy+0x27>
 8048438:       c6 c6 c5                mov    $0xc5,%dh
 804843b:       8a fd                   mov    %ch,%bh
 804843d:       c5 d8 c6 ce 8b          vshufps $0x8b,%xmm6,%xmm4,%xmm1
 8048442:       a0 aa 90 90 90          mov    0x909090aa,%al
 8048447:       90                      nop
 ...
 804844f:       90                      nop

The obfuscation technique claimed to be used here is called instruction camouflage (see this paper). Can someone explain what is it and how does it works ?

6
  • In general, a mask is a value applied on a bitfield via a bitwise operation, to read, set or reset a particular bit.
    – Ange
    Commented Apr 10, 2013 at 7:29
  • I agree the name must be changed. But, it seems to be extremely difficult to find a proper one. The point of this technique is mainly to conceal the executed code from a simple naive static analysis. For now, after discussions, "code cloaking" is the best I can come with... but I don't know if it would be accepted.
    – perror
    Commented Apr 10, 2013 at 7:39
  • For me (personally), being understood by most of the community is more important than using a perfect - but new - word that no one has heard of and that might be misinterpreted (for that reason, I tend to use 'ROP' even if I personally prefer 'return-to-libc'). And 'hiding' and 'obfuscating' are way more widespread than 'cloaking' IMHO.
    – Ange
    Commented Apr 10, 2013 at 7:49
  • So, you would advise "code hiding" ? (code obfuscation cannot be an option because it cannot tag one technique among others). It is perfectly okay with me also. (Post-scriptum: 'ROP' and 'return-into-libc' are really two different techniques)
    – perror
    Commented Apr 10, 2013 at 7:56
  • I found a reference about instruction camouflage. Though it is not a very well known paper, their name seems okay (I hope this is the last time I modify this... I'm just a mess, sorry).
    – perror
    Commented Apr 15, 2013 at 13:15

2 Answers 2

12

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.

13
  • 3
    Personally I've never heard the term "code masking" nor does Google or Wikipedia turn up any hints. Could you link to some resource where this term is actually used? Commented Apr 9, 2013 at 9:23
  • I don't know how to call this obfuscation. I couldn't find a proper generic name for this. Give some name, I'll change it in the question and in the answer.
    – perror
    Commented Apr 9, 2013 at 9:30
  • I'm used to it being called naive encryption since I assume you mean the question to cover more than xor? E.g some simple combinations of rotations and xor? Otherwise it's a xor cipher. I actually can't think of a really good name for ciphers that are trivially reversible. Given your explanation the same sort of answer would cover any complex cipher scheme as well. I.e the operations between your entry point and breakpoint could be arbitrarily complex but would still fall to your technique. It doesn't rely on the cipher being trivial. Commented Apr 9, 2013 at 9:42
  • 2
    I think we just call this "self-modification". Commented Apr 9, 2013 at 10:14
  • 1
    Knowing the algorithm and key don't change the fact that it's a decryption. I wasn't suggesting a new word, I was mentioning the word I'd expect.
    – Ange
    Commented Apr 10, 2013 at 7:27
2

This is also commonly known as an encryption wrapper. I'm sure there are several other similar names used in the industry.

The actual code isn't as important as the concept. The plaintext code is prepended (in executive order) by a decryption stub responsible for decoding the body of the code. In this way, the main code body (payload in the case of malware) is encrypted, and thus doesn't have constant bytes. The decoder stub itself remains constant in this example, though polymorphism is a later evolution that regenerates the encoder and decoder so that they, too, contain no constant bytes. By lessening the number of constant bytes between copies of the code, detection signature exposure is reduced.

Decoder stubs can offer decompression as well.

This mechanism got heavy use in the early days of self-replicating PC viruses. These were labeled with the characteristic of being self-encrypting. It is still used in today by some subversive software.

Importantly, native code isn't the only code that can be 'wrapped' in this fashion.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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