deroko

imports are easy to fix

Rating: 2 votes, 2.50 average.
Well I read post at openrce posted by blabberer in X-Code thread here at woodmann (http://www.woodmann.com/forum/showthread.php?t=10635) and saw interesting discussion between Rolf Rolles (waz up man ) and Kris Kaspersky debating which way of generic fixing is better. Kris votes for adding loader, but Rolf likes clean import to have good disasm in IDA. Infact I had this same problem a few months ago, it was easy to locate all APIs and add loader, who cares, app works, well it works and you don't have to analyse it as long as registration scheme is located in the wraper, but what if registration is located in program itself and you have to analyse it? It would be mess and boring task in IDA not seeing real APIs Basically that small discussion was inspiration to write this blog post

Look at this messy fixed import. It looks like, for example, armadillo shuffled IAT or maybe ActiveMARK v6.xx fixed IAT. But take a closer
look where are APIs located:

Code:
00BBC368 >7C80A447  kernel32.QueryPerformanceCounter
00BBC36C >7E450702  USER32.MessageBoxA

kernel32.QueryPerformanceCounter = BBC364
user32.MessageBoxA               = BBC368
You might wonder how did I get this to work? Using API loader? No!!!

What I have used here is 1API = 1 image import descriptor concept which I use to fix imports always. Basically this is how it works:

Code:
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            
        DWORD   OriginalFirstThunk;         
    };
    DWORD   TimeDateStamp;                  
    DWORD   ForwarderChain;                 
    DWORD   Name;
    DWORD   FirstThunk;                     
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
According to PE specification OriginalFirstThunk points to API names, but if it is 0 then FirstThunk is pointing to API names, also FirstThunk is used to know where to store API addresses.


So what we shall do to make this concept work?

1. Build OriginalFirstThunk such that it only points to one API name
2. place RVA in FirstThunk where we want API loaded
3. When import table is built simply walk firstthunk and set it to
specific value != 0 as windows loader will deny loading image if
address to which FirstThunk is pointing is 0. Weird?! I didn't find
anything in PE specification about this behaviour

Lets see some code snipets from this library which you may find in src of my GenericUnpacker and import engine at http://deroko.phearless.org

First we define some struct which will hold our imports:

Code:
import_struct           struct
        is_address      dd      ?               <--- RVA where we want API address to be
                                                     writen by windows loader
        is_dlllen       dd      ?               <--- len of dll name including terminating 0
        is_apilen       dd      ?               <--- len of API string including terminating 0
                                                     or 4 if API is imported by ordinal
        is_dllname      db      256     dup(0)  <--- dllname (ASCII)
        is_apiname      db      256     dup(0)  <--- API name or ordinal | 0x80000000
import_struct           ends
Now it's very simply to fix IAT:

By number of this structs we know how many IMAGE_IMPORT_DESCRIPTORs we will have, but
also tnhx to lengths stored in structs we can estimate size of newly built IAT including
APIs aswell.

OriginalFirstThunk will always point to API name or ordinal and also will take one more
DWORD for 0 to tell windows loader that there are no more APIs to be loaded.


EBX = memory used for IMAGE_IMPORT_DESCRIPTOR
EDI = pointer where we write dll, api names or ordinals and is calculated
as EBX + (number_of_import_structs + 1) * sizeof (IMAGE_IMPORT_DESCRIPTOR)

Code:
                        sub     edx, size import_struct
                        
__cycle_main_loop:      add     edx, size import_struct
                        cmp     [edx.is_address], 0
                        je      __done_building
                
                        ;copy dll name
                        mov     esi, edi
                        sub     esi, new_iat_mem
                        add     esi, iat_sec_rva
                        
                        mov     [ebx.id_name], esi 
                        lea     esi, [edx.is_dllname]
                        mov     ecx, [edx.is_dlllen]
                        rep     movsb
                        
                        ;write original first thunk
                        mov     esi, eax
                        sub     esi, new_iat_mem
                        add     esi, iat_sec_rva
                        
                        mov     [ebx.id_originalfirstthunk], esi
                        
                        mov     esi, dword ptr[edx.is_apiname]
                        test    esi, 80000000h
                        jz      __api_has_name
                        mov     [eax], esi
                        jmp     __firstthunk         

__api_has_name:
                        mov     esi, edi
                        sub     esi, new_iat_mem
                        add     esi, iat_sec_rva
                        mov     [eax], esi
             
                        lea     esi, [edx.is_apiname]
                        add     edi, 2
                        mov     ecx, [edx.is_apilen]
                        rep     movsb

__firstthunk:                        
                        mov     esi, [edx.is_address]
                        mov     [ebx.id_firstthunk], esi
                        
                        add     ebx, size import_directory
                        add     eax, 8
                        jmp     __cycle_main_loop
When this small loop is done, all we have to do is to walk all first_thunks and set them
to != 0 so win loader can actually load this import table.

With this concept you don't have to write sorting algos to get nice and clean IAT, who
cares where are APIs located. In my, aspr2.3 dumper for example, I scan original code
for APIs that are not stolen, then I go for stolen APIs and write them into array
and I don't care if I have something like this:

MessageBoxA
GetModuleHandleA
RegOpenKeyExA

etc...

After this is done, then I go for APIs located in poly oep, or other stolen procedures
which are located in markers. At this point IAT looks like nightmare and importrec nor
any other public known engine can fix this IAT... But 1API = 1IDD concept fixes this
without a problem!!!

Think about it when writing unpacker and protection developers think too when
you try to make "hard" IAT to stop importrec, you will lose one way or another
Remember that not many people are using it lately

Submit "imports are easy to fix" to Digg Submit "imports are easy to fix" to del.icio.us Submit "imports are easy to fix" to StumbleUpon Submit "imports are easy to fix" to Google

Updated October 23rd, 2007 at 11:53 by deroko

Categories
Uncategorized

Comments