Results 1 to 6 of 6

Thread: Bridge them all

  1. #1
    Red wine, not vodka! ZaiRoN's Avatar
    Join Date
    Oct 2001
    Location
    Italy
    Posts
    922
    Blog Entries
    17

    Bridge them all

    Today I’m going to tell you something about the last malware I checked (MD5 0C17E03F41289E47EEB5D0F3F1F48C9C).

    The exe file imports few functions only, but the malware calls a lot of APIs. The author uses a special trick to call an API function, he creates a sort of bridge between the first instruction and the rest of the code of the function itself. The first instruction is executed directly from the stack, then a jmp instruction (the bridge) will lead you to the second instruction (and the rest of the code) of the function. I think I’ve already seen the trick somewhere but unfortunately I don’t remember where… maybe a specific packer or just something similar, I don’t know. If you have seen this trick before just drop me a comment, thx!

    The malware is packed, but inside the unpacked file there’s something strange:



    The exe is full of calls to NULL value. I’m pretty sure that it’s not an error occorred during the unpacking process; there’s something at the beginning of the exe able to fix the addresses. I started my analysis from the first lines of the unpacked file.

    The Import Table is really small but spying inside the strings window I found a lot of common API strings. There’s a big list of functions, and they are divided into some groups; one group containing kernel32 functions, another one with user32 and so on. Working a little with some cross references I got the point I was looking for. It’s time to describe how the malware changes all the “call NULL” instructions.

    First of all the malware gains access to kernel32 base address:

    Code:
    4013D5    mov  edi, large fs:30h  ; PEB
    4013DC    mov  edi, [edi+0Ch]     ; PEB+0x00c   Ldr : Ptr32 _PEB_LDR_DATA
    4013DF    mov  edi, [edi+0Ch]     ; +0x00c InLoadOrderModuleList : _LIST_ENTRY
    4013E2    jmp  short loc_401404
    
    4013E4 check_current_module:
    4013E4    mov  eax, edi    ; eax points to current _LDR_MODULE structure
    4013E6    add  eax, 2Ch
    4013E9    push [ebp+arg_0]        ; unicode "kernel32.dll"
    4013EC    push dword ptr [eax+4]  ; current module name inside InLoadOrderModuleList
    4013EF    call Compare_UNICODE_Strings
    4013F4    or   eax, eax
    4013F6    jnz  short strings_are_not_equal
    4013F8    mov  eax, edi           ; LDR_MODULE of the module I was looking for
    4013FA    mov  eax, [eax+18h]     ; He gets the BaseAddress!!!
    4013FD    pop  edi
    4013FE    leave
    4013FF    retn 4
    
    401402 strings_are_not_equal:
    401402    mov  edi, [edi]        ; jump to next module structure
    401404 loc_401404:
    401404    cmp  dword ptr [edi+18h], 0          ; Is BaseAddress 0?
    401408    jnz  short check_current_module
    40140A    xor  eax, eax
    40140C    pop  edi
    40140D    leave
    40140E    retn 4
    Quite common way, but quite uncommon inside a malware… at least from my not so experienced perspective. Anyway, once it has the right BaseAddress tha malware starts bridge-ing all the necessary functions.



    It’s everything inside this call. It takes four parameters, we can ignore the first one pushed into the stack. What about the others?
    - eax represents the BaseAddress of a module, in this case ntdll
    - 404040 points to a sequence of strings, in this case the first one is “RtlZeroMemory”
    - 406000 represents an address inside the malware
    The procedure is called each time the malware needs to bridge a group of functions, all of them belong to a specific module. In this specific case it works with ntdll’s functions. The list of the functions starts from 0×404040 address:



    The routine contains a loop running until all the functions inside the current group are not all bridged. Here is how the first function is bridged (the sub routine starts at 0×401411):
    1. It takes VirtualAlloc starting address via Kernel32’s ExportTable
    2. It gets the number of bytes of the first instruction of VirtualAlloc. On my XP machine VirtualAlloc starts with a two byte length instruction “MOV EDI, EDI”
    3. It subtracts 7 from ESP value. 7 is obtained adding 5 (a fixed value) to the number of bytes of VirtualAlloc first instruction (2+5=7)
    4. It copies the first two bytes of VirtualAlloc’s code inside the word pointed by the new stack pointer value
    5. If the length of the first instruction is one byte only the malware checks for a possible active breakpoint comparing the byte with 0xCC value; quite useless check at this point…
    6. It sets the byte pointed by ESP+2 to 0xE9
    7. It fills the final 4 of 7 bytes obtaining:



    You have the first instruction of VirtualAlloc at 0×12FDF5, then the jump instruction will lead you directly at the second instruction of VirtualAlloc. Now you understand why it decreases ESP value by 7, two bytes for the first instruction and 5 for the jump. Starting from 0×12FDFC you have the old untouched stack.
    8. It gets the length of the first instruction of the function to bridge. In this specific case the name of the function is RtlZeroMemory and the length is 1
    9. It adds 5 to the obtained value
    10. It calls VirtualAlloc passing trought the stack. It calls 0×12FDF5, and it allocs 6 bytes. 6 is the value that comes from point #9 (5+1=6)
    11. It copies the first instruction of RtlZeroMemory inside the allocated memory space
    12. An anti breakpoint check occours this time because the first instruction is one byte only
    13. It sets the second byte inside the allocated memory space to 0xE9 (again, a jmp instruction)
    14. It fills the rest of the bytes:



    Here is the bridge! It’s like what happened to VirtualAlloc, the allocated memory space contains the first instruction of RtlZeroMemory and a jump to the rest of the code
    15. It restores the original stack pointer value simply adding 7 to the current ESP value
    16. It returns the starting address of the allocated memory space (in this case 0×320000)

    To sum up, the routine bridges the function and returns a memory address. The address will be saved starting from 0×406000 which is another parameter passed to the routine. If you don’t remind all the parameters you can take a look some lines above.
    So, starting from 0×406000 you’ll have a series of dwords, each one containing a pointer to a memory allocated space; these are the values used to replace all the NULL calls. Now I finally know why after the unpacking process I still had a series of “call NULL” instructions.

    Is it really necessary to bridge everything?
    Yes if the author wants to fool an automatic analysis. I don’t know if the trick works or not, but it’s the only reasonable thing I can think of.
    On the other hand, he can’t stop a complete human analysis because once you know how it works it’s pretty easy to convert all the “call NULL” instructions into the right ones; a simple idc script will solve the puzzle.

    It’s a nice piece of malware to analyse btw, it has some interesting routines inside!

  2. #2
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,516
    Blog Entries
    1
    protector do that kind API_redirection against Import restiring. ya?

  3. #3
    Red wine, not vodka! ZaiRoN's Avatar
    Join Date
    Oct 2001
    Location
    Italy
    Posts
    922
    Blog Entries
    17
    That's a good reason eval, but the question is still the same: does it worth the effort?
    A mind is like a parachute. It doesnt work if it's not open.

  4. #4
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,516
    Blog Entries
    1
    so-so!
    everything worth SO-SO.
    writing malware!? - BUD-BUD

  5. #5
    From a reverers' point of view it's no big deal of course, one could patch the LDE to return a zero instruction length or patch the appropiate jump to prevent the redirection.

    It could confuse newbies who use int3s on the first API instruction, but they'll figure out as well what's happening very soon.

    Malware primarily does not have the reversers as enemy, malware's fighting against generic, automated tools; sandboxes and similar stuff. And of course, such "dumb" approaches might work perfectly fine against several AV engines - considering that, it might be "worth the effort".

    A protector would at least have to mutate (better virtualize, metamorph and the like) and verify its own integrity (thus preventing the occurrence of "magic jumps").

    Just my five cents...

  6. #6
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,143
    Blog Entries
    5
    The first instruction is executed directly from the stack, then a jmp instruction (the bridge) will lead you to the second instruction (and the rest of the code) of the function. I think I’ve already seen the trick somewhere but unfortunately I don’t remember where maybe a specific packer or just something similar, I don’t know. If you have seen this trick before just drop me a comment, thx!
    That sort of looks like API redirection where the first several instructions are run in program code before jumping to the remainder of the function. I haven't seen it run off the stack before, or with quite that implementation, but I think Asprotect and similar did that stub redirection trick, no?

    I first saw this in PEX, where the first several instructions were embedded in SMC. As anom mentions, this would also negate breakpoints set on the start of the API.

    How PEX 0.99 Redirects API's
    http://www.woodmann.com/forum/showthread.php?t=1595

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •