Avatar

Blog (pg. 21)

  • Published on
    Sometimes it is necessary to extend the functionality of a program to which you don't have the source code. This tutorial focuses on adding functionality to a compiled Windows Portable Executable file, but the idea can probably be implemented on other compiled binaries. Adding simple functionality can be achieved directly in 'code caves' within the PE file by adding the assembly code directly to the exe to perform the operation (i.e. use a hex editor with assembler to render the opcodes directly into some empty space in the exe file) The more complex the functionality, the more assembly code this will require, which needs bigger code caves and takes more coding on your part. You can create bigger code caves by adding new sections to the file, but that is not the topic of this tutorial. An easier way, I have found, is to code the extra functionality in a DLL, which is best coded in C++/C as these are easier to import into the target app. You should use the extern "C" macro on your exports to make them asm friendly (no mangling) and specify 'declspec(dllexport)' to make the compiler put the function in the exports.. For example: (AddOns.h)
    #ifdef ADDONS_EXPORTS
    #define ADDONS_API extern "C" __declspec(dllexport)
    #else
    #define ADDONS_API __declspec(dllimport)
    #endif
    
    ADDONS_API bool someFunction(LPCTSTR someTextParam);
    You can code the core of the functionality in the methods defined in your DLL and then the only assembly you need to code is loading your DLL and calling the functions. The above function for example, will be in a DLL called 'AddOns.dll' and take 1 paramater (a pointer to a string). In assembly code you can load the dll using the LoadLibrary function and find the address of the function using GetProcAddress. If the exe does not import these functions, read my other blog post on Finding the address of GetProcAddress.
    push &"AddOns.dll"                ; address of string for the DLL, in a code cave
    call &LoadLibraryA                ; address of the imported/loaded LoadLibraryA function
    push &"someFunction"              ; address of string for the function, in a code cave
    push eax                          ; HMODULE AddOns.dll (returned from LoadLibrary)
    call &GetProcAddressA             ; address of the imported/loaded GetProcAddressA function
    push &"SomeString"                ; address in the app to the parameter you want to pass
    call eax                          ; call the function in the dll (returned from GetProcAddress)
    add esp, 4                        ; clear the stack
    jmp &returnAddress                    ; go back to the original code?
    Since C functions use the cdecl calling convention by default, you have to clean the stack of your params when you are finished and if your function returns a value, it will be in EAX. Once you have put the above code in a cave somewhere, you simply need to jmp to it at the appropriate point in the original exe and then have it jmp back to the best place in the code to give control back to the normal program flow when you have finished.
  • Published on
    When working within the confines of a compiled PE file (.exe) you often want to call external functions stored in DLLs. If the DLL/function was imported when the exe was compiled then it will be referenced in the imports table; DLLs/functions in the imports table will be loaded by the Windows loader when the PE is executed, you can then use the IAT (import address table) to get the address to call these functions. However, most of the time the DLL and/or function you want to use was not originally imported by the PE file and will therefore not have an entry in the IAT. You can load a DLL manually by calling LoadLibrary and GetProcAddress in your assembly code, passing in the name of the DLL and the name of the function you wish to load respectively. This method relies on the exe at least having the two imports: Kernel32.LoadLibrary Kernel32.GetProcAddress Without these two imports, you have to do something a little more elaborate. The method I will outline relies on the exe having only one import: Kernel32.GetModuleHandle Which most Win32 PE files will import. This function returns HMODULE, which is actually the base address of the loaded DLL. (If the file you are working on doesn't import any of these functions, you can try using the standard Kernel32.dll base address of 0xBFF70000 or use some other technique, such as reading the PEB, TEB or using SEH, try Googling.) Assuming you now have the base address of Kernel32.dll you can read the PE headers of the image to find the exported GetProcAddress. Once you have GetProcAddress, you can use it to find LoadLibrary and you then have the two functions you need to load any number of DLLs/functions.
    mov eax,myExe.&"Kernel32.dll"                       ;Address of ASCII "Kernel32.dll" - already in imports
    push eax
    mov eax,<jmp.&Kernel32.GetModuleHandleA>            ;IAT Thunk
    call eax
    push eax                                            ;hMod
    add eax,dword ptr ds:[eax+3c]                       ;eax+e_lfanew
    mov ebx,dword ptr ds:[eax+78]                       ;PE+78h IMAGE_DIRECTORY_ENTRY_EXPORT
    mov eax,dword ptr ss:[esp]                          ;hMod
    add eax,ebx                                         ;VA to IMAGE_EXPORT_DIRECTORY
    pop edx                                             ;save hMod
    push eax                                            ;save Exports Section address
    push edx                                            ;hMod on top
    mov ebx,dword ptr ds:[eax+20]                       ;Read IMAGE_EXPORT_DIRECTORY+20h (AddressOfNames[])
    pop eax                                             ;hMod
    xor ecx,ecx                                         ;reset counter
    :label1
    inc ecx                                             ;count++
    push ebx                                            ;save RVA AddressOfNames[]
    push eax                                            ;save hMod
    add eax,ebx                                         ;VA AddressOfNames[count]
    mov ebx,dword ptr ds:[eax]                          ;RVA FunctionName
    mov eax,dword ptr ss:[esp]                          ;hMod
    add eax,ebx                                         ;VA of FunctionName
    mov esi,eax
    pop eax                                             ;hMod
    pop ebx                                             ;RVA AddressOfNames[]
    mov edi,myExe.&"GetProcA"                           ;ASCII "GetProcA" - Put this in a cave
    cmps dword ptr ds:[esi],dword ptr es:[edi]          ;(DWORD cmp) FunctionName = "GetP"
    je short myExe.&label2                              ;match, check next half
    add ebx,4                                           ;else, next RVA (4byte RVAs)
    jmp short myExe.&label1                             ;loop
    :label2
    add ebx,4                                           ;next RVA (4byte RVAs)
    cmps dword ptr ds:[esi],dword ptr es:[edi]          ;(2nd DWORD cmp) FunctionName = "rocA"
    jnz short myExe.&label1                             ;if not, loop again
    pop edx                                             ;VA Exports Section
    mov ebx,dword ptr ds:[edx+1c]                       ;read IMAGE_EXPORT_DIRECTORY+1Ch (AddressOfFunctions[])
    push eax                                            ;hMod
    mov eax,ecx                                         ;ordinal+1
    dec eax                                             ;ordinal
    mov ecx,4                                           ;4byte RVAs
    mul ecx                                             ;ordinal*4
    add ebx,eax                                         ;move ordinal*4 bytes in AddressOfFunctions[]
    pop eax                                             ;hMod
    push eax                                            ;kernel32.77E60000
    add eax,ebx                                         ;RVA FunctionAddress
    pop ebx                                             ;hMod
    push ebx                                            ;save for later - kernel base
    add ebx,dword ptr ds:[eax]                          ;VA FunctionAddress
    push ebx                                            ;entry GetProcAddress
    The above code snippet leaves you with the VA of GetProcAddress on the stack (and in EBX). You can the go on to find LoadLibrary..
    push myExe.&"LoadLibraryA"                      ;Address of ASCII "LoadLibraryA" - in a cave
    push dword ptr ss:[esp+8]                       ;hMod Kernel32 - still on the stack from above
    call ebx                                        ;call GetProcAddress - returns address to EAX
    push eax                                        ;Save to stack
    You have now loaded GetProcAddress and LoadLibrary and have them both on the stack ready for use.
  • Published on
    The following example shows how you can use a bubble sort in Assembly language to sort some numbers:
    .386
    .model flat,stdcall
    
    option casemap:none
    
    .data
    example_data db 1,3,4,5,2,5,7,4,6,0
    num_of_elements db 10
    
    .code
    start:
        mov eax, dword ptr[num_of_elements] ;whatever the programmer entered
        dec eax                             ;less one (since 10 elements = 0-9)
        mov dword ptr[num_of_elements], eax ;save the new value
    
        lea eax, example_data               ;point eax to start addr
        xor ebx, ebx                        ;reset (data reg 1)
        xor edx, edx                        ;reset (data reg 2)
        xor ecx, ecx                        ;reset counter
    
    stillsort:
        mov bl, byte ptr[eax]               ;get 1 byte
        mov dl, byte ptr[eax+1]             ;and the byte to its right
        cmp bl, dl                          ;compare the 2
        jg notdone                          ;if byte 2 &gt; byte 1, not sorted, go sort
        push eax                            ;save where we are
        push ecx                            ;save counter
        lea eax, example_data               ;go back to start (for test)
        xor ecx, ecx                        ;reset counter
        jmp test_sorted                     ;go test the whole list
    
    notdone:
        mov byte ptr[eax], dl               ;put byte 2 in byte 1 position
        mov byte ptr[eax+1], bl             ;put byte 1 in byte 2 position
        inc eax                             ;go to next byte
        inc ecx                             ;count
        cmp ecx, dword ptr[num_of_elements] ;10 elements (0-9)
        jnz stillsort                       ;still sorting (no reset)
        lea eax, example_data               ;did all 10 elements, go again from start
        xor ecx, ecx                        ;reset counter
        jmp stillsort                       ;back to sort code
    
    test_sorted:
        mov bl, byte ptr[eax]               ;get 1 byte
        mov dl, byte ptr[eax+1]             ;and the byte to its right
        cmp bl, dl                          ;compare
        jg nope                             ;if byte 2 &gt; byte 1 the whole list isnt sorted
        inc eax                             ;try next byte
        inc ecx                             ;count
        cmp ecx, dword ptr[num_of_elements] ;10 elements (0-9)
        jz done                             ;all 10 elements are sorted
        jmp test_sorted                     ;or loop
    
    nope:
        pop ecx                             ;get the back the old count
        pop eax                             ;back to the last byte we were on
        inc eax                             ;but 1 more now
        inc ecx                             ;increase counter
        cmp ecx, dword ptr[num_of_elements] ;10 elements (0-9)
        jnz stillsort                       ;sorting
        lea eax, example_data               ;it was the last element, back to start
        xor ecx, ecx                        ;reset counter
        jmp stillsort                       ;sorting
    
    done:
        pop ecx                             ;clear stack
        pop eax                             ;clear stack
        xor eax, eax                        ;exit code 0
        ret
    end start