純匯編如何獲得LoadLibrary地址和實現GetProcAddress? 100分求教---***


我有代碼,可是不懂匯編,看不懂。
想做個遠程程序注入的,不想靠Dll,想直接寫代碼,不過如果用C++直接寫成程序的話,代碼太大。
所以我想到了用匯編實現一些簡單的代碼。

哪位牛人幫我解釋下一下代碼:

函數:(實現GetProcAddress的功能)
00400164    60                      pushad
00400165    8B6C24 24               mov ebp,dword ptr ss:[esp+24]
00400169    8B45 3C                 mov eax,dword ptr ss:[ebp+3C]
0040016C    8B7C05 78               mov edi,dword ptr ss:[ebp+eax+78]
00400170    01EF                    add edi,ebp
00400172    8B4F 18                 mov ecx,dword ptr ds:[edi+18]
00400175    8B5F 20                 mov ebx,dword ptr ds:[edi+20]
00400178    01EB                    add ebx,ebp
0040017A    49                      dec ecx
0040017B    8B348B                  mov esi,dword ptr ds:[ebx+ecx*4]
0040017E    01EE                    add esi,ebp
00400180    31C0                    xor eax,eax
00400182    99                      cdq
00400183    AC                      lods byte ptr ds:[esi]
00400184    84C0                    test al,al
00400186    74 07                   je short SmallLea.0040018F
00400188    C1CA 0D                 ror edx,0D
0040018B    01C2                    add edx,eax
0040018D  ^ EB F4                   jmp short SmallLea.00400183
0040018F    3B5424 28               cmp edx,dword ptr ss:[esp+28]
00400193  ^ 75 E5                   jnz short SmallLea.0040017A
00400195    8B5F 24                 mov ebx,dword ptr ds:[edi+24]
00400198    01EB                    add ebx,ebp
0040019A    66:8B0C4B               mov cx,word ptr ds:[ebx+ecx*2]
0040019E    8B5F 1C                 mov ebx,dword ptr ds:[edi+1C]
004001A1    01EB                    add ebx,ebp
004001A3    032C8B                  add ebp,dword ptr ds:[ebx+ecx*4]
004001A6    896C24 1C               mov dword ptr ss:[esp+1C],ebp
004001AA    61                      popad
004001AB    C3                      retn


調用代碼:

004001AC    31DB                    xor ebx,ebx
004001AE    64:8B43 30              mov eax,dword ptr fs:[ebx+30]
004001B2    8B40 0C                 mov eax,dword ptr ds:[eax+C]
004001B5    8B70 1C                 mov esi,dword ptr ds:[eax+1C]
004001B8    AD                      lods dword ptr ds:[esi]
004001B9    8B40 08                 mov eax,dword ptr ds:[eax+8]
004001BC    5E                      pop esi
004001BD    68 8E4E0EEC             push EC0E4E8E
004001C2    50                      push eax
004001C3    FFD6                    call esi                           ; 匯編實現的GetProcAddress
004001C5    66:53                   push bx
004001C7    66:68 3332              push 3233
004001CB    68 7773325F             push 5F327377
004001D0    54                      push esp
004001D1    FFD0                    call eax                           ; LoadLibrary("ws2_32");
004001D3    68 CBEDFC3B             push 3BFCEDCB
004001D8    50                      push eax
004001D9    FFD6                    call esi                           ; 匯編實現的GetProcAddress
004001DB    5F                      pop edi
004001DC    89E5                    mov ebp,esp
004001DE    66:81ED 0802            sub bp,208
004001E3    55                      push ebp
004001E4    6A 02                   push 2
004001E6    FFD0                    call eax                           ; ws2_32.WSAStartup(2);
004001E8    68 D909F5AD             push ADF509D9
004001ED    57                      push edi
004001EE    FFD6                    call esi                           ; SmallLea.00400164

13 个解决方案

#1


嗯。不明白你說的不靠DLL是說不加載kernel32.dll的意思么?應該所有的應用程序都會加載到這個動態庫吧,我是說再windows xp 系統,其它的不曉得

#2


樓主隨便去找段shellcode參考一下吧,網上很多

#3


不會這么高深的東東 幫頂

#4


引用 2 樓 jhlong 的回復:
樓主隨便去找段shellcode參考一下吧,網上很多


這就是從ShellCode里抄出來的,不過我看不懂。

#5


引用樓主 weizehua 的回復:
我有代碼,可是不懂匯編,看不懂。
想做個遠程程序注入的,不想靠Dll,想直接寫代碼,不過如果用C++直接寫成程序的話,代碼太大。
所以我想到了用匯編實現一些簡單的代碼。


在確定目標被注入進程裝載 kernel32.dll 的前提下,在 Windows XP 環境下,LoadLibraryW 的裝載地址是固定不變的,為 7C80ACD3H ,如果你不想依賴目標進程的裝載 kernel32.dll 的與否,你可以直接拷貝 LoadLibraryW 的代碼,不過估計這樣不太可能實現,LoadLibraryW 在內部又 CALL 了 kernel32.dll 的LoadLibraryExW,LoadLibraryExW 在內部又 CALL 了 ntdll.dll 的一些函數,所以LZ想完全手寫代碼是不現實的,手寫 GetProcAddress 的代碼也是不現實的,GetProcAddress 在內部也 CALL 了 ntdll.dll 的一些函數,所以目標進程也需要裝載 ntdll.dll,所以你貼出的代碼就沒必要去解釋其含義了。

下面是 LoadLibraryW 的反匯編碼:


7C80ACD3 >  8BFF            mov     edi, edi
7C80ACD5    55              push    ebp
7C80ACD6    8BEC            mov     ebp, esp
7C80ACD8    6A 00           push    0
7C80ACDA    6A 00           push    0
7C80ACDC    FF75 08         push    dword ptr [ebp+8]
7C80ACDF    E8 0D6EFFFF     call    LoadLibraryExW
7C80ACE4    5D              pop     ebp
7C80ACE5    C2 0400         retn    4


下面是 GetProcAddress 的反匯編碼:


7C80AC28 >  8BFF            mov     edi, edi
7C80AC2A    55              push    ebp
7C80AC2B    8BEC            mov     ebp, esp
7C80AC2D    51              push    ecx
7C80AC2E    51              push    ecx
7C80AC2F    53              push    ebx
7C80AC30    57              push    edi
7C80AC31    8B7D 0C         mov     edi, dword ptr [ebp+C]
7C80AC34    BB FFFF0000     mov     ebx, 0FFFF
7C80AC39    3BFB            cmp     edi, ebx
7C80AC3B    0F86 571C0000   jbe     7C80C898
7C80AC41    57              push    edi
7C80AC42    8D45 F8         lea     eax, dword ptr [ebp-8]
7C80AC45    50              push    eax
7C80AC46    FF15 8812807C   call    dword ptr [<&ntdll.RtlInitString>]     ; ntdll.RtlInitString
7C80AC4C    8D45 0C         lea     eax, dword ptr [ebp+C]
7C80AC4F    50              push    eax
7C80AC50    6A 00           push    0
7C80AC52    8D45 F8         lea     eax, dword ptr [ebp-8]
7C80AC55    50              push    eax
7C80AC56    6A 00           push    0
7C80AC58    FF75 08         push    dword ptr [ebp+8]
7C80AC5B    E8 C2ECFFFF     call    7C809922
7C80AC60    50              push    eax
7C80AC61    E8 B7FFFFFF     call    <jmp.&ntdll.LdrGetProcedureAddress>
7C80AC66    85C0            test    eax, eax
7C80AC68    0F8C DE830000   jl      7C81304C
7C80AC6E    6A 00           push    0
7C80AC70    FF75 08         push    dword ptr [ebp+8]
7C80AC73    E8 AAECFFFF     call    7C809922
7C80AC78    3945 0C         cmp     dword ptr [ebp+C], eax
7C80AC7B    0F84 12600300   je      7C840C93
7C80AC81    8B45 0C         mov     eax, dword ptr [ebp+C]
7C80AC84    5F              pop     edi
7C80AC85    5B              pop     ebx
7C80AC86    C9              leave
7C80AC87    C2 0800         retn    8

#6



7C80ACDF    E8 0D6EFFFF     call    LoadLibraryExW


幫你分析一下這句你就知道完全手寫代碼是不可能的,
E8 0D6EFFFF 是相對跳轉,
FFFF6E0DH 是負數,
也就是向之前的代碼 CALL,
我們來計算一下,
FFFF6E0DH - 1H = FFFF6E0CH
二進制取反 = 000091F3H
也就是 7C80ACDFH 這一行將會從下一條指令開頭算起,
從 7C80ACE4H 向后 000091F3H 個位置,
7C80ACE4H - 000091F3H = 7C801AF1H
7C801AF1H 正好是 LoadLibraryExW 的地址,
CALL 指令將會 CALL 到 LoadLibraryExW,
你如果把這些代碼直接拷貝,
這一行將會 CALL 一個什么都不是的代碼,
所也建議LZ不要手寫代碼。

#7


樓主研究一下TEB  PEB的結構,另外研究一下PE文件格式
這段代碼的細節我也不太記得清了,以前仔細分析過,現在都是拿來直接用了

大致的思路是查找PEB結構里的模塊鏈表,總共有3個鏈表,這里用到的是按模塊加載順序的那條
鏈表第一個節點值NTDLL.DLL, 第二個節點是KERNEL32.DLL
定位到KERNEL32.DLL模塊首地址
再去通過函數名稱的一個自己實現的簡單的HASH遍歷導出表,(在CALL ESI里)獲取到目標函數的地址
我記性不好,可能有不對的地方

這段代碼和地址無關,可以放在任意地方執行,樓主放心用吧

《0day:軟件漏洞分析技術》這本書里有很詳細的解釋,樓主可以去買一本參考一下

#8


;注意masm編譯,注意這個程序不能直接運行,編譯完成后od加載code3之前運行一次是加密,運行完dump出來就是shellcode了!
.386p
.model flat, stdcall
.code
start: 
assume fs:flat, gs:flat
;這里直接寫代碼

;------------------------B.j.H's split-line-----------------------------------
;首先建立一個在shellcode中需要用到的字符表他應該包括
;LoadLibraryA
;user32
;MessageBoxA
;ExitProcess
;B.J.H        當然為了彈出的Msgbox有個性可以添加這樣一字符串,用來彈框框
;這些字符統統壓入堆棧以便調用!
;所以我們代碼的前面是
;------------------------B.j.H's split-line-----------------------------------
push 0048h                        ;B.J.H
push 2e4a2e42h                    ;
push 00737365h                    ;ExitProcess
push 636f7250h
push 74697845h
push 0041786fh                    ;MessageBoxA
push 42656761h
push 7373654dh
push 00323372h                    ;user32
push 65737500h
push 41797261h                    ;LoadLibraryA
push 7262694ch
push 64616f4ch
mov edx,esp                       ;保存字符串首地址
;上面是一個函數表!注意壓入的字符格式,注意堆棧是倒過來的!慢慢調試可以感覺出來的!
;最后一據代碼是保存字符串表的的入口(也就是首地址)
;------------------------B.j.H's split-line-----------------------------------
;獲得Kernel的基地址(這一段很多地方都能找到!)不做解釋了!
xor eax,eax
mov eax,dword ptr FS:[030h]
mov eax,DWORD PTR [eax+0ch]
mov esi,DWORD PTR [eax+01ch]
lodsd
mov eax,dword ptr [eax+8h]
;------------------------B.j.H's split-line-----------------------------------
;現在eax中存放的就是kernel32的基地址了!
;當處到這里我就不知道該怎么出來了!得到基地址到底有什么用呢!不知道!呵呵!時間久了!
;忙忙的閱讀一些資料!自然而然的就懂了!...我不是那種一看資料就明白的那種具有潛質的大
;鳥,只是一點一點體會的小菜鳥!
;下面先寫一個調用就是
;------------------------B.j.H's split-line-----------------------------------
push eax                          ;保存kernel32.dll基地址
push edx                          ;傳入需要查詢函數名地址
push 0ch                          ;函數名長度
call getapi                       ;調用函數得到函數入口
;------------------------B.j.H's split-line-----------------------------------
pop ebx                           ;彈出堆棧里的的函數名地址(是之前建立的)
add ebx,0dh                    ; 加上字符長度得到下一個需要使用的字符串的
push ebx                         ;參數"user32"
call eax                           ;調用LoadLibraryA("user32"),加載
                                       ;user32.dll,且eax中是從函數調用返回的user32的基地址
;------------------------B.j.H's split-line-----------------------------------
add ebx,07h                     ; 繼續得到下一個需要使用的字符串。下面的幾個調用不詳細說了... ...
push ebx                          ; 
push 0bh                          ;  
call getapi                        ;調用getaddr函數獲取MessageBoxA函數地址.
;------------------------B.j.H's split-line-----------------------------------
pop ebx                           ; 
add ebx,018h                   ; 
push 0h                           ; 
push ebx                          ;
push ebx                          ;
push 0h                           ;
call eax                          ;調用MessageBoxA
;------------------------B.j.H's split-line-----------------------------------
mov edx,0ch                     ; 
pop eax                            ; 
sub ebx,edx                      ; 
push ebx                          ;
push edx                          ;
call getapi                        ;調用getaddr函數獲取exitprocess函數地址.
call eax                            ;調用exitprocess
;------------------------B.j.H's split-line-----------------------------------
;下面這個才是重點!(個人認為)
;寫一個根據dll的基地址查找API函數入口 的函數方便調用
;函數說明:此函數包括兩個傳入參數,一個是基地址,另一個是需要查詢的函數名字符串首地址
;------------------------B.j.H's split-line-----------------------------------
getapi:
mov ebx,eax                                  ;eax存放的傳入的基地址
add eax,03ch                                 ;定位PE頭位置地址
mov eax,dword ptr [eax]               ;獲得PE頭偏移地址
add eax,ebx                                   ;計算PE頭VA
cmp dword ptr [eax],00004550h    ;驗證PE文件的合法性
jne Err                                            ;不合法跳轉
mov eax,dword ptr [eax+078h]     ;導出表地址獲得
add eax,ebx                                  ;計算導出表入口VA
push eax                                       ;保存導出表入口VA
mov ecx,eax                                  ;令ecx指向導出表
mov ecx,dword ptr [ecx + 014h]   ;找出導出表中函數個數作為循環值
mov eax,dword ptr [eax + 020h]   ;找出函數名字符串地址表的偏移
add eax,ebx                                  ;計算函數名字符串地址表的VA
push ebp                                        ;保存ebp寄存器,寄存器不夠用,借用一下,呵呵!
mov ebp,eax                                  ;ebp保存函數名字符串地址表的VA
xor edx,edx                                   ;edx清0用於存放函數索引

LoopFind:
push ecx;                                       ;保存ecx 循環次數
mov eax,dword ptr[eax]                ;獲取函數名字符串偏移
add eax,ebx                                  ;計算函數字符串VA
mov edi,eax                                   ;把VA賦值給edi 准備比較
mov esi,dword ptr [esp + 014h]   ;這個地方要算好了!函數內部有3個push,每個push為4個字節一個12個字節
                                                      ;字符串地址放在call外部倒數第二個push(這個自己用控制好第幾個參數是自己定的)
               ;也就是說從push 字符串地址到這個命令行之間有16個字節被push進入棧中。是不是就是+10H呢
               ;注意我們這里用了一個函數,不是jmp,函數調用的時候會有一個push eip用於返回!
               ;所以我們在計算的時候這個push不能忘,最后計算得到esp+14h中所放的就我們要查的函數名字符的地址
mov ecx,dword ptr [esp + 010h]     ; 計算同上,這里是給ecx賦值,函數名的長度。ecx被改變了
                                                        ;(后面,在loop命令之前要恢復的ecx,這個是計數器,硬性規定,呵呵!)
cld                              ;
repz cmpsb                                     ;字符串比較 esi 和 edi 比較
jne FindNext                                   ;比較,如果不是,則取下一個函數

add esp,4                                     ;找到往下執行 相當與pop ecx。無關緊要了!
mov eax,dword ptr [esp + 04h]    ;恢復導出函數表入口
mov eax,dword ptr [eax + 01ch]   ;獲得函數地址表入口偏移
                                                     ;我在這里缺少了一步,大多數情況不會有影響,具體的是哪一步,
                                                     ;深究的同志可以看看關於函數導出表的函數查詢方式
add eax,ebx                      ;計算函數地址表入口VA
shl edx,2                        ;函數索引*函數地址(默認為4個字節) 鑒戒別人的,很妙的一招相當與乘以4
add eax,edx                      ;函數地址表基址+(函數索引)
mov eax,dword ptr[eax]           ;獲得函數入口地址偏移
add eax,ebx                      ;計算VA
jmp Found

FindNext:
inc edx                                ;計數器加一
add ebp,4h                         ;函數名字符串地址表的VA指向下一個函數名地址
mov eax,ebp                       ; 函數名地址的VA賦值到eax
pop ecx                              ;恢復ecx 循環次數
loop LoopFind                     ;loop 繼續循環查找

Err:
xor eax,eax                       ;沒有找到,或者出錯,eax清理。

Found: 
pop ebp                              ;恢復ebp
pop ecx                               ;不能再恢復eax了!彈到ecx好了!
ret 4                                    ; 返回 且 add esp 4 
                                           ;這個是因為我們調用完函數時需要利用之前我們自己建立函數名字符表。
end start

#9


引用 5 樓 renxu350 的回復:
引用樓主 weizehua 的回復:
我有代碼,可是不懂匯編,看不懂。
想做個遠程程序注入的,不想靠Dll,想直接寫代碼,不過如果用C++直接寫成程序的話,代碼太大。
所以我想到了用匯編實現一些簡單的代碼。


在確定目標被注入進程裝載 kernel32.dll 的前提下,在 Windows XP 環境下,LoadLibraryW 的裝載地址是固定不變的,為 7C80ACD3H ,如……



你要是不會  就不要誤導別人好不好?
http://bbs.pediy.com/showthread.php?t=121226

#10


引用 9 樓 blueapple1987 的回復:
你要是不會 就不要誤導別人好不好?
http://bbs.pediy.com/showthread.php?t=121226


你既是KANXUE高手,為何還來這里顯擺?
我等未有學習過此項技術,自知是菜鳥級別,才做此菜鳥回答,OK ?
對看雪早已經久仰已久,
雖然你技術高超,但你的言語顯示你缺乏真正高手的涵養,
你幸災樂禍於別人沒學過,而自己卻學過的東西,
你是在自己自我貶低你自己一個KANXUE高手的人品,
你只能算是人品低下的技術高手,
就是這100分全給了你又如何 ?
就算全世界服務器的操作系統全部被你掛了一次馬又如何 ?
我鄙視這種人品低下的技術高手 !
拜托你言語能否不要隱藏着刺人的言語 OK ?!

#11


多謝大家的回答,不過我乍一看,不懂。。。。

#12


引用 9 樓 blueapple1987 的回復:
引用 5 樓 renxu350 的回復:

引用樓主 weizehua 的回復:
我有代碼,可是不懂匯編,看不懂。
想做個遠程程序注入的,不想靠Dll,想直接寫代碼,不過如果用C++直接寫成程序的話,代碼太大。
所以我想到了用匯編實現一些簡單的代碼。


在確定目標被注入進程裝載 kernel32.dll 的前提下,在 Windows XP 環境下,LoadLibraryW 的裝……


恩,我想要的。

#13


         
               add    edi, ebx          ;edi = API NAME
          
          push  ecx
          mov    ecx, [esp + 4 + 4]

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com