老掉牙的東西--Api地址的“手動”獲取 (8千字)
api函式地址的獲取
by Hume/冷雨飄心
這是一個老題目了,如果我們不用任何引入庫,能否在程式中呼叫api函式?當然可以!方法有很多,你可能早就知道了,如果你已經瞭解了,就此打住,這是為還不瞭解這一技術而寫.另外這也是病毒必用的技巧之一,如果你對病毒技術感興趣,接著看下去.
這裡假設你瞭解PE的基本結構,如果還不懂,找點資料來看看,到處都是呦.
在幾乎每個病毒的開頭都用下面的語句:
call delta
delta:
pop ebp
sub ebp,offset delta
mov dword ptr [ebp+offset appBase],ebp
讓我們考慮一下程式的執行情況,如果下面的程式碼由編譯器自動編譯連線,那麼程式執行的基址一般是400000h,如果是在Nt下執行,那麼基址可能不同,比如從100000h開始,不用擔心,作業系統的Loader會自動為你重定位.但是這裡停下來讓我們看一下,如果你想要把這段程式碼附加到其他程式的後面並想讓其正確執行的話,就不是那麼簡單了,因為你的程式碼可能要從555588h處開始執行,而在沒有得到宿主程式許可的情況下期望作業系統自動為你修正偏移錯誤是不可能的,既然有非常的目的,就得費點力氣,自己搞定重定位.而上面的程式碼就是首先得到eip指標,也是delta在程式執行時的實際偏移,然後減掉程式碼頭到delta的偏移從而得到你的程式碼的真正基址,後面對於偏移的操作都應以這個真正的偏移為準.這就是你上面看到的.如果不明白,就仔細想一下,nothing
difficult!下面的例子演示了這一點,並沒有全部重定位,因為這只是技術演示.
現在回到本文的正式內容,要想獲得api的地址,得首先獲得諸如kernel32.dll,user32.dll的基址,然後再找到真正的函式地址.如何獲得基址和函式地址呢呢?有幾種方法
1)搜尋宿主的引入表獲得GetModuleHandleA函式和GetProcAddress的地址,然後透過他返回系統dll的基址.因為很多程式都要使用這兩個函式,因此在某些情況下是可行的,如果宿主沒有使用GetProcAddress,那你就不得不搜尋Export表了.
2)直接獲得kernel32.dll的基址,然後再搜尋Export表獲得GetProcAddress和LoadLibraryA的地址,然後我們就能得到任何想呼叫的函式地址.
3)硬編碼呼叫函式,比如在9X下GetModuleHandleA的地址一般是BFF7****.
第一種和第三種方法存在相容性的問題,假如宿主沒有呼叫GetModuleHandleA,那麼你就不能獲得基址,別的就更別想了...硬編碼問題更大,作業系統不同則不能執行了,比如9X下可能在有些計算機上正常,但肯定不能在Nt/2K下執行...
第二種方法相容性比較好,因此作以介紹.
一點背景:在PE Loader裝入我們的程式啟動後堆疊頂的地址是是程式的返回地址,肯定在Kernel中!
因此我們可以得到這個地址,然後向低地址縮減驗證一直到找到模組的起始地址,驗證條件為PE頭不能大於4096bytes,PE
header的ImageBase值應該和當前指標相等,嘿嘿,簡單吧,而且相容性還不錯.
要獲得Api的地址首先要獲得GetModuleHandle,LoadLibraryA,GetProcAddress的地址,這是透過搜尋Export表來實現的,具體原理就是PE
Export表的結構,如果瞭解了PE結構就很簡單了.下面我加了點註釋,沒有最佳化程式碼,是為了便於理解.
好,這一部分結束了!
這是一個例子,沒有用任何預引入函式,加了一條invoke InitCommonControls是為了在2K下也能正常執行,否則不能在2K下不載入!
程式得到MessageBoxA的地址然後顯示一個訊息框,目的在於演示,重要部分加了註釋,很好明白.
.586
.model flat, stdcall
option casemap :none ; case sensitive
include c:\hd\hd.h
include c:\hd\mac.h
;;--------------
GetApiA proto :DWORD,:DWORD
;;--------------
.CODE
appBase dd ?
k32Base dd ?
lpApiAddrs label near
dd
offset sGetModuleHandle
dd
offset sGetProcAddress
dd
offset sExitProcess
dd
offset sLoadLibrary
dd
0
sGetModuleHandle db "GetModuleHandleA",0
sGetProcAddress db "GetProcAddress",0
sExitProcess db "ExitProcess",0
sLoadLibrary db "LoadLibraryA",0
sMessageBoxA db "MessageBoxA",0
aGetModuleHandle dd 0
aGetProcAddress dd 0
aExitProcess
dd 0
aLoadLibrary
dd 0
aMessageBoxA
dd 0
u32 db
"User32.dll",0
k32 db
"Kernel32.dll",0
sztit db "By Hume,2002",0
szMsg0 db "Hey,Hope
U enjoy it!",0
;;-----------------------------------------
__Start:
invoke InitCommonControls
call delta
delta:
pop ebp
;得到delta地址
sub ebp,offset delta
;因為在其他程式中基址可能不是預設的所以需要重定位
mov dword ptr [ebp+offset appBase],ebp
;呵呵仔細想想
mov ecx,[esp]
;返回地址
xor edx,edx
getK32Base:
dec ecx
;逐位元組比較驗證
mov dx,word ptr [ecx+IMAGE_DOS_HEADER.e_lfanew]
;就是ecx+3ch
test dx,0f000h
;Dos Header+stub不可能太大,超過4096byte
jnz getK32Base
;加速檢驗
cmp ecx,dword ptr [ecx+edx+IMAGE_NT_HEADERS.OptionalHeader.ImageBase]
jnz getK32Base
;看Image_Base值是否等於ecx即模組起始值,
mov [ebp+offset k32Base],ecx
;如果是,就認為找到kernel32的Base值
lea edi,[ebp+offset aGetModuleHandle]
lea esi,[ebp+offset lpApiAddrs]
lop_get:
lodsd
cmp eax,0
jz End_Get
push eax
push dword ptr [ebp+offset k32Base]
call GetApiA
;獲取API地址
stosd
jmp lop_get
End_Get:
push offset u32
call dword ptr [ebp+offset aLoadLibrary]
;在程式空間載入User32.dll
lea EDX,[EBP+OFFSET sMessageBoxA]
push edx
push eax
mov eax,dword ptr [ebp+aGetProcAddress]
;用GetProcAddress獲得MessageBoxA的地址
call eax
;呼叫GetProcAddress
push 40h+1000h
;style
push offset sztit
;title
push offset szMsg0
;訊息內容
push 0
call eax
;一個訊息框產生了...嘿嘿
;有理由為此高興吧,因為我們沒有預先引入
@@:
;這些函式
push 0
call [ebp+aExitProcess]
;-----------------------------------------
K32_api_retrieve proc Base:DWORD ,sApi:DWORD
push edx
;儲存edx
xor eax,eax
;此時esi=sApi
Next_Api:
;edi=AddressOfNames
mov esi,sApi
xor edx,edx
dec edx
Match_Api_name:
mov bl,byte ptr [esi]
inc esi
cmp bl,0
jz foundit
inc edx
push eax
mov eax,[edi+eax*4]
;AddressOfNames的指標,遞增
add eax,Base
;注意是RVA,一定要加Base值
cmp bl,byte ptr [eax+edx]
;逐字元比較
pop eax
jz Match_Api_name
;繼續搜尋
inc eax
;不匹配,下一個api
loop Next_Api
jmp no_exist
;若全部搜完,即未存在
foundit:
pop edx
;edx=AddressOfNameOrdinals
shl eax,1
;*2得到AddressOfNameOrdinals的指標
movzx eax,word ptr [edx+eax] ;eax返回指向AddressOfFunctions的指標
ret
no_exist:
pop edx
xor eax,eax
ret
K32_api_retrieve endp
;-----------------------------------------
GetApiA proc Base:DWORD,sApi:DWORD
local ADDRofFun:DWORD
pushad
mov edi,Base
add edi,IMAGE_DOS_HEADER.e_lfanew
mov edi,[edi]
;現在edi=off PE_HEADER
add edi,Base
;得到IMAGE_NT_HEADERS的偏移
mov ebx,edi
mov edi,[edi+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress]
add edi,Base
;得到edi=IMAGE_EXPORT_DIRECTORY入口
mov eax,[edi+1ch]
;AddressOfFunctions的地址
add eax,Base
mov ADDRofFun,eax
;ecx=NumberOfNames
mov ecx,[edi+18h]
mov edx,[edi+24h]
add edx,Base
;edx=AddressOfNameOrdinals
mov edi,[edi+20h]
add edi,Base
;edi=AddressOfNames
invoke K32_api_retrieve,Base,sApi
mov ebx,ADDRofFun
shl eax,2
;要*4才得到偏移
add eax,ebx
mov eax,[eax]
add eax,Base
;加上Base!
mov [esp+7*4],eax
;eax返回api地址
popad
ret
GetApiA endp
;-----------------------------------------
END __Start
;------------------------------------------End all
相關文章
- 智慧手環運動軌跡API獲取2021-10-28API
- 智慧手環心率API獲取2021-10-27API
- 獲取配置的mock地址2018-03-04Mock
- Windows 8系統有線網路卡自動獲取IP地址2016-08-18Windows
- 智慧手環計步API獲取2021-10-29API
- 智慧手環主動預警水文資料API獲取2021-11-05API
- 用Golang做點自動化的東西2019-03-25Golang
- Android手機怎麼獲取印表機的IP地址呢2015-07-22Android
- 智慧手環睡眠資料API獲取2021-11-01API
- 獲取URL地址2018-11-15
- 不要偷黑客的東西2011-08-23黑客
- servlet中手動獲取spring的bean2014-10-28ServletSpringBean
- java獲取本機的ip地址2020-04-06Java
- iphone 獲取地址的詳細資訊2021-01-26iPhone
- 獲取本地的IP地址(內網)2014-08-19內網
- DHCP獲取IP地址的過程2012-02-28
- Oracle獲取連線的IP地址2015-10-27Oracle
- 什麼是自動獲取IP地址2019-08-05
- 如何設定自動獲取ip地址2021-09-11
- 使用Unified Communications Managed API獲取Lync線上會議的連結地址2013-08-11NifiAPI
- 爬取githubs——登入後的東西(兩種方法)2018-11-10Github
- w10如何設定自動獲取ip地址_w10怎麼自動獲取ip地址2019-12-19
- 最簡單的C# 獲取 MAC 地址 IP 地址2010-03-01C#Mac
- 智慧手環報文資料API獲取2021-11-09API
- 智慧手環體溫資料API獲取2021-11-03API
- 智慧手環圍欄資料API獲取2021-11-04API
- VBS 的基礎性的東西2014-08-13
- 初學者的東西:Transoft's Server All 1.02破解
(3千字)2001-01-08Server
- FineReport移動端如何獲取地址位置2017-01-24
- javascript獲取url地址的幾種方式2017-03-20JavaScript
- js獲取url地址中的引數2013-09-11JS
- as3獲取url地址的引數2010-04-16S3
- 如何使用 Go 獲取你的 IP 地址2024-09-18Go
- saltstack獲取IP地址2019-01-03
- 獲取IP地址方法2017-10-10
- 獲取IP地址命令2007-09-19
- 未來學東西的思路2021-12-31
- 筆試不會的東西2020-11-09筆試