2013년 10월 1일 화요일

call function without importing kernerl32.dll

nasm -f win32 thunked.asm
link /subsystem:console thunked.obj -entry:WinMain

-----
    ; ------------------------------------------------
    ; call.asm - finds kernel32.dll in memory and
    ; searches it's export table for LoadLibraryA()
    ; and GetProcAddress(). From there, calling
    ; functions that haven't been imported is trivial.
    ;
    ; :-)
    ;
    ; Assembled with:
    ;   nasm call.asm -fwin32 -o call.obj
    ;   gcc call.obj -o call.exe
    ;
    ; AdhesiveBall - August/2010
    ; ------------------------------------------------

    [BITS 32]
    global _WinMain@16



    section .data
       WorkedMessage    db "Hello from an unimported function!", 0
      
       LoadLibraryName db "LoadLibraryA", 0
       LoadLibraryAddr dd 0xFFFFFFFF
      
       GetProcAddressName db "GetProcAddress", 0
       GetProcAddressAddr dd 0xFFFFFFFF
      
       MessageBoxName db "MessageBoxA", 0
       MessageBoxAddr dd 0xFFFFFFFF
      
       User32Name db "user32.dll", 0
       User32Addr db 0xFFFFFFFF
      
       Kernel32Addr   dd 0xFFFFFFFF

    section .text

    ; -----------------------------------------------
    ; void *FindKernel32Base(void)
    ; tries to find the base address of kernel32.dll
    ; returns NULL on error
    ; -----------------------------------------------
    FindKernel32Base:
       mov    eax, [fs:0x30]   ; address of PEB
       mov    eax, [eax + 0x0C]   ; PEB->Ldr
       mov    eax, [eax + 0x1C]    ; Ldr->InMemoryOrderModuleList (first element is ntdll.dll)
       mov    eax, [eax]      ; InMemoryOrderModuleList->Flink (second element is kernel32.dll)
       mov    eax, [eax + 0x08]   ; DllBase
       cmp word [eax], 'MZ'   ; check for MZ header
       je    FindKernel32Base_end
       xor    eax, eax      ; zero eax if not found
    FindKernel32Base_end:
       ret

      
    ; ------------------------------------------------------
    ; void *LoadFunction(HMODULE module, char *FunctionName)
    ; attempts to find the address of function by
    ; walking module's Export Address Table
    ; ------------------------------------------------------
    LoadK32Function:
       push    ebp
       mov    ebp, esp
       sub   esp, 12      ; make room for 3 DWORDS
      
       ; look at my stack frame, my stack frame's amazing
       ;------------------------------------
       ;          +-----------------------+
       ; ebp-0x0C | PE Header             |
       ;          +-----------------------+
       ; ebp-0x08 | Export table addr     |
       ;          +-----------------------+
       ; ebp-0x04 | AddressOfNames        |
       ;          +-----------------------+
       ; .....
       ;          +-----------------------+
       ; ebp+0x08 | kernel32 base address |
       ;          +-----------------------+
       ; ebp+0x0C | function name         |
       ;          +-----------------------+
       ;------------------------------------
      
      
      
       mov    edi, [ebp + 0x08]    ; edi = DosHeader
      
       ; -------------------------
       ; verify MZ and PE headers
       ; -------------------------
       cmp word [edi], 'MZ'   
       jne    LoadK32Function_fail
       mov    edx, edi
       add    edx, [edi + 0x3C]    ; module + DosHeader->e_lfanew (edx = PeHeader)
       cmp word [edx], 'PE'
       jne    LoadK32Function_fail
       mov   [ebp - 0x0C], edx   ; save the PE header
      
       ; ------------------------------
       ; find the real addr of the EAT
       ; ------------------------------
       mov    eax, [edx + 0x78]    ; OptionalHeader.DataDirectory[0].VirtualAddress
       add    eax, dword [ebp + 0x08] ; add the offset to the base address
       mov   [ebp - 0x08], eax   ; save it!
      
       ; ----------------------------------------
       ; find the real address of export names
       ; ----------------------------------------
       mov    eax, [eax + 0x20]   ; eax is still addr of EAT (0x20 = offset to ADdressOfNames)
       add    eax, dword [ebp + 0x08]
       mov    [ebp - 0x04], eax
      
      
       ; --------------------------------
       ; start looking for names!
       ; --------------------------------
       xor ecx, ecx
       LoadK32Function_loop_names:
          mov    edx, [ebp - 0x08]   ; EAT
          cmp    ecx, [edx + 0x18]   ; NumberOfNames
          jge LoadK32Function_fail
         
          ; --------------------------------------
          ; find the address of the function name
          ; --------------------------------------
          mov   ebx, [ebp - 0x04]   ; AddressOfNames
          mov   ebx, [ebx + ecx * 4]   ; RVA of string
          add   ebx, [ebp + 0x08]
         
          ; compare 'em!
          push dword [ebp + 0x0C]   ; FunctionName
          push    ebx      ; name of entry
          call    strcmp
          cmp    eax, 1
          je    LoadK32Function_found_api
         
          inc    ecx
          jmp    LoadK32Function_loop_names
         
    LoadK32Function_found_api:
       ;------------------------------------------------------
       ; success! now all that's left is to go from the
       ; AddressOfNames index to the AddressOfFunctions index
       ; -----------------------------------------------------
      
       ; First thing's first, find the AddressOfNameOrdinals address
       mov    eax, [ebp - 0x08]
       mov   eax, [eax + 0x24] ; AddressOfNameOrdinals offset
       add   eax, [ebp + 0x08]
      
       ; Now we gotta look up the ordinal corresponding to our api
       xor    ebx, ebx
       mov   bx, [eax + ecx * 2] ; ecx * 2 because it's an array of WORDS
      
       ; Next we find the AddressOfFunctions array
       mov   eax, [ebp - 0x08]
       mov   eax, [eax + 0x1C] ; AddressOfFunctions offset
       add   eax, [ebp + 0x08]
      
       ; and last we find the address of our api!
       mov   eax, [eax + ebx * 4]
       add   eax, [ebp + 0x08]
      
       jmp    LoadK32Function_end
    LoadK32Function_fail:
       xor    eax, eax
    LoadK32Function_end:
       mov    esp, ebp
       pop    ebp
       ret    8

      
      
      
      
      
      
      
    ; -------------------------------------------------------------
    ; unsigned int RVAToFileOffset(
    ; IMAGE_NT_HEADERS *ntHeader, unsigned long virtualAddr);
    ;
    ; Converts a relative virtual address to an offset in the file
    ; -------------------------------------------------------------
    ;RvaToFileOffset:
    ;   push    ebx
    ;   mov    eax, [esp + 0x08] ; eax = ntHeader
    ;   mov    ebx, [esp + 0x0C] ; ebx = virtualAddr
    ;   push    ecx
    ;   push    edx
    ;   xor    ecx, ecx
    ;   mov    cx, [eax + 0x06]    ; ecx = number of sections
    ;   lea    edx, [eax + 0xF8]    ; edx = first section
    ;   RvaToFileOffset_loop_sections:
    ;      push    ecx      ; used as a temporary variable throughout the loop
    ;     
    ;      ; -------------------------------------------------------------
    ;      ; check if the virtual address resides in the current function
    ;      ; -------------------------------------------------------------
    ;      cmp    ebx, [edx + 0x0C]   ; if(virtualAddr < section->VirtualAddress) continue;  
    ;      jl    RvaToFileOffset_continue
    ;      mov    ecx, [edx + 0x0C]  
    ;      add    ecx, [edx + 0x08]   ; ecx = section->VirtualAddress + section->VirtualSize
    ;      cmp    ebx, ecx      ; if(virtualAddr >= ecx) continue;
    ;      jge    RvaToFileOffset_continue
    ;  
    ;   RvaToFileOffset_DEBUGLABEL:
    ;      ; -------------------
    ;      ; Success! It's here
    ;      ; -------------------
    ;      sub    ebx, [edx + 0x0C] ; find the offset from the beginning of the section's virtual addr
    ;      add    ebx, [edx + 0x14] ; add it to the PointerToRawData member
    ;      jmp    RvaToFileOffset_success
    ;     
    ;;   RvaToFileOffset_continue:
    ;      add    edx, 0x28      ; edx += sizeof(IMAGE_SECTION_HEADER)
    ;      pop    ecx         ; restore for use as a counter
    ;      loop    RvaToFileOffset_loop_sections
    ;  
    ;   xor    eax, eax   ; baww
    ;   jmp    RvaToFileOffset_end
    ;  
    ;RvaToFileOffset_success:
    ;   pop    ecx   ; ecx will be on the stack 'coz of the loop so we need to fix it
    ;   mov    eax, ebx
    ;RvaToFileOffset_end:
    ;   pop    edx
    ;   pop    ecx
    ;   pop    ebx
    ;   ret    8
      
      
      
      
      
      
      
      
      
      
    ; -------------------------------------------------
    ; int strcmp(char *a, char *b)
    ; returns 1 if the two strings are equal, 0 if not
    ; -------------------------------------------------
    strcmp:
       push ebx
       strcmp_loop:
          mov    eax, [esp + 0x08]
          mov    al, byte [eax]
          mov    ebx, [esp + 0x0C]
          cmp    al, byte [ebx]
          jne    strcmp_not_equal
          cmp    al, 0
          je    strcmp_equal
          inc   dword [esp + 0x0C]
          inc    dword [esp + 0x08]
          jmp    strcmp_loop
      
       strcmp_not_equal:
          mov    eax, 0
          jmp    strcmp_end
      
       strcmp_equal:
          mov    eax, 1
         
    strcmp_end:
       pop    ebx
       ret    8
      
      
    ; -----------------------------------------------
    ; kinda bloated but meh does it's job
    _WinMain@16:
       call    FindKernel32Base
       cmp    eax, 0
       je    _WinMain_failed
       mov    [Kernel32Addr], eax
      
       ; find LoadLibrary()
       push    LoadLibraryName
       push    dword [Kernel32Addr]
       call    LoadK32Function
       cmp    eax, 0
       je    _WinMain_failed
       mov    [LoadLibraryAddr], eax
      
       ; find GetProcAddress()
       push    GetProcAddressName
       push    dword [Kernel32Addr]
       call    LoadK32Function
       cmp    eax, 0
       je   _WinMain_failed
       mov   [GetProcAddressAddr], eax
      
       ; load user32.dll
       push    User32Name
       call   [LoadLibraryAddr]
       cmp   eax, 0
       je   _WinMain_failed
       mov   [User32Addr], eax
      
       ; find MessageBox()
       push   MessageBoxName
       push dword [User32Addr]
       call    [GetProcAddressAddr]
       cmp    eax, 0
       je    _WinMain_failed
       mov   [MessageBoxAddr], eax
      
       push    0
       push    WorkedMessage
       push    WorkedMessage
       push    0
       call    [MessageBoxAddr]
      
    _WinMain_worked:
    ;   push    0
    ;   push    WorkedMessage
    ;   push    WorkedMessage
    ;   push    0
    ;   call    _MessageBoxA@16
    ;   jmp    _WinMain_end
    _WinMain_failed:
    ;   push    0
    ;   push    FailedMessage
    ;   push    FailedMessage
    ;   push    0
    ;   call    _MessageBoxA@16
    _WinMain_end:
       ret    16

file offset

Offset = va - imagebase address

2013년 9월 29일 일요일

[nasm\print hello

nasm -f win32 hello.asm

------


C:\work>link hello.obj msvcrt.lib
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.


C:\work>hello
Hello, World

C:\work>

2013년 9월 27일 금요일

stack


entry point

dumpbin /headers \Windows\bfsvc

Dump of file \Windows\bfsvc.exe

PE signature found

File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
             14C machine (x86)
               4 number of sections
        4A5BBFB3 time date stamp Tue Jul 14 01:13:55 2009
               0 file pointer to symbol table
               0 number of symbols
              E0 size of optional header
             102 characteristics
                   Executable
                   32 bit word machine

OPTIONAL HEADER VALUES
             10B magic # (PE32)
            9.00 linker version
            DE00 size of code
            2000 size of initialized data
               0 size of uninitialized data
            4149 entry point (01004149)
            1000 base of code
            F000 base of data
         1000000 image base (01000000 to 01011FFF)
            1000 section alignment
             200 file alignment

2013년 9월 26일 목요일