api暴力獲取

看雪資料發表於2015-11-15

這篇是老調重彈了。看老羅之作,見原程式(asm.chm中)未完,用了很長時間補完,想想長期蒙受了各位大蝦的賜教,特感激!!


.386
.model flat, stdcall
option casemap:none
include masm32includewindows.inc

GetKernelBase   proto   :DWORD
GetApiAddress   proto   :DWORD, :DWORD

.data
szMyMsg             db  "--=   暴力搜尋記憶體空間獲得 Api 的線性地址  =--", 13, 10, 13, 10,
                        "請注意:", 13, 10,
                        "* 本對話方塊的線性地址是透過暴力搜尋得來 *", 13, 10, 13, 10,
                        "老羅的繽紛天地",13, 10, "http://www.luocong.com/", 0
szMyCaption         db  "老羅的病毒基礎教程系列 by LC", 0
aKernel32Base       dd  0
szUser32            db  "user32.dll", 0
szExitProcess       db  "ExitProcess", 0
aExitProcess        dd  0
szLoadLibraryA      db  "LoadLibraryA", 0
aLoadLibraryA       dd  0
szGetProcAddress    db  "GetProcAddress", 0
aGetProcAddress     dd  0
szMessageBoxA       db  "MessageBoxA", 0
aMessageBoxA        dd  0

.code
main:    
    call delta
delta:
    pop ebp
    sub ebp, offset delta

    ;獲得 Kernel32.dll 的基地址:
    invoke GetKernelBase, [esp]
    mov aKernel32Base, eax

    ;獲得 Kernel32.dll 中的所需的 Api 的線性地址:
    invoke GetApiAddress, aKernel32Base, addr szExitProcess
    mov aExitProcess, eax
    invoke GetApiAddress, aKernel32Base, addr szLoadLibraryA
    mov aLoadLibraryA, eax
    invoke GetApiAddress, aKernel32Base, addr szGetProcAddress
    mov aGetProcAddress, eax

    ;載入 User32.dll :
    push offset szUser32
    call [ebp + aLoadLibraryA]

    ;獲得 User32.dll 中的 MessageBoxA 的線性地址:
    push offset szMessageBoxA
    push eax
    call [ebp + aGetProcAddress]
    mov aMessageBoxA, eax

    ;呵呵,千呼萬喚始出來,高興了吧??
    push MB_OK or MB_ICONINFORMATION
    push offset szMyCaption
    push offset szMyMsg
    push NULL
    call [ebp + aMessageBoxA]

    ;退出:
    push 0
    call [ebp + aExitProcess]


;**************************************************
;函式功能:查詢 Kernel32.dll 的基地址
;**************************************************
GetKernelBase   proc uses esi edi dwKernelRet:DWORD
    LOCAL dwReturn: DWORD

    mov edi, dwKernelRet                ; edi = 堆疊頂
    and edi, 0ffff0000h                 ; 用 AND 獲得初始頁
    .while TRUE
        .if word ptr [edi] == IMAGE_DOS_SIGNATURE       ; 等於“MZ”嗎?
            mov esi, edi                                ; Yes, next...
            add esi, [esi + IMAGE_DOS_HEADER.e_lfanew]  ; 就是 esi + 3ch
            .if word ptr [esi] == IMAGE_NT_SIGNATURE    ; 等於“PE”嗎?
                mov dwReturn, edi                       ; Yes, we got it.
                .break
            .endif
        .endif
        ;以下等同於sub edi, 010000h,即每次減少64k:
        dec edi
        xor di, di
        .break  .if edi < 070000000h    ; 基地址一般不可能小於70000000h
    .endw
    mov eax, dwReturn

    ret
GetKernelBase   endp


;**********************************************************************
;函式功能:從記憶體中 Kernel32.dll 的匯出表中獲取某個 API 的入口地址
;**********************************************************************

GetApiAddress   proc uses ecx ebx edx esi edi hModule:DWORD, szApiName:DWORD
    LOCAL dwReturn: DWORD
    LOCAL dwApiLength: DWORD

    mov dwReturn, 0

    ;計算 API 字串的長度(帶尾部的0)
    mov esi, szApiName
    mov edx, esi
Continue_Searching_Null:
    cmp byte ptr [esi], 0           ; 是否為 Null-terminated char ?
    jz We_Got_The_Length            ; Yeah, we got it.  :)
    inc esi                         ; No, continue searching.
    jmp Continue_Searching_Null     ; searching.......
We_Got_The_Length:
    inc esi                         ; 呵呵, 別忘了還有最後一個“0”的長度。
    sub esi, edx                    ; esi = API Name size
    mov dwApiLength, esi            ; dwApiLength = API Name size

    ;從 PE 檔案頭的資料目錄獲取輸出表的地址
    mov esi, hModule
    add esi, [esi + 3ch]
    assume esi: ptr IMAGE_NT_HEADERS
    mov esi, [esi].OptionalHeader.DataDirectory.VirtualAddress
    add esi, hModule
    assume esi:ptr IMAGE_EXPORT_DIRECTORY 
    mov edi,szApiName   
   mov ecx,[esi].AddressOfNameOrdinals
   add ecx,hModule;取得AddressOfNameOrdinals陣列的指標
   ;invoke RVAToFileMap,hModule,[esi].AddressOfNames
   mov ebx,[esi].AddressOfNames
    add ebx,hModule;取得AddressOfNames陣列的指標,特要注意AddressOfNames為指向指標的指標陣列(個人之見),且都為RVA
Continue_look:
    mov eax,[ebx]   
   add eax,hModule
   push ebx
   mov ebx,eax     

    push edi
   push ecx
   mov ecx,dwApiLength;字串的長度
Continue:
   mov al,[edi]
   mov ah,[ebx]
   xor al,ah;字串的比較
   jnz again
   dec ecx
   inc edi
   inc ebx
   jcxz found
   jmp  Continue
again:   
   pop ecx
   pop edi
   pop ebx
    add ebx,4 ;ebx指向AddressOfNames名的陣列,值為雙字型,所以加4
    add ecx,2;ecx指向序數陣列,值是字型別,所以加2
   jmp Continue_look
found:
    pop ecx
   pop edi
   pop ebx
   
    mov ebx,ecx
    mov dx,[ebx] ;ebx指向序數陣列,值是字型別
    movzx edx,dx;因此將其轉換成雙字
    mov ebx,[esi].AddressOfFunctions 
   add ebx,hModule;取得AddressOfFunctions的指標
   shl edx, 2:索引乘以4 (AddressOfFunctions 陣列中每個元素都是4位元組大小) 
    add edx,ebx;然後加上陣列首地址
   mov eax,[edx];eax就是所要函式的RVA了
   add eax,hModule  
    ret
GetApiAddress       endp

end main

相關文章