青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

elva

調用未知DLL中的導出函數

 

不知道諸位看官是否有過這樣的經歷:在不經意之間發現一個DLL文件,它里邊有不少有趣的導出函數——但是由于你不知道如何調用這些函數,所以只能大發感慨而又無能為力焉。固然有些知名的DLL可以直接通過搜索引擎來找到它的使用方式(比如本文中的例子ipsearcher.dll),不過我們誠然不能希望自己總能交到這樣的好運。所以在本文中,李馬希望通過自己文理不甚通達的講解能夠給大家以授人以漁的效果。

先決條件

閱讀本文,你需要具備以下先決條件:

  • 初步了解匯編語言,雖然你并不一定需要去讀懂DLL中導出函數的匯編代碼,但是你至少應該了解諸如push、mov這些常用的匯編指令。
  • 一個能夠查看DLL中導出函數的工具,Visual Studio中自帶的Dependency Walker就足夠勝任了,當然你也可以選擇eXeScope。
  • 一個調試器。理論上講VC也可以完成調試的工作,但它畢竟是更加針對于源代碼一級調試的工具,所以你最好選擇一個專用的匯編調試器。在本文中我用的是OllyDbg——我不會介紹有關這個調試工具的任何東西,而只是簡要介紹我的調試過程。

準備好了嗎?那么我們做一個熱身運動吧先。

熱身——函數調用約定

這里要詳細介紹的是有關函數調用約定的內容,如果你已經了解了這方面的內容,可以跳過本節。

你可能在學習Windows程序設計的時候早已接觸過“函數調用約定”這個詞匯了,那個時候你所了解的內容可能是一個籠統的概念,內容大抵是說函數調用約定就是指的函數參數進棧順序以及堆棧修正方式。譬如cdecl調用約定是函數參數自右而左進棧,由調用者修復堆棧;stdcall調用約定亦是函數參數自右而左進棧,但是由被調用者修復堆棧……噢不,這太晦澀了——在源代碼上我們是無法看到這些東西的!

那么我們別無選擇,只有深入到匯編一層了。考慮以下C++代碼:

#include <stdio.h>

int __cdecl max1( int a, int b )
{
    return a > b ? a : b;
}

int __stdcall max2( int a, int b )
{
    return a > b ? a : b;
}

int main()
{
    printf( "max( 1, 2 ) of cdecl version: %d\n", max1( 1, 2 ) );
    printf( "max( 1, 2 ) of stdcall version: %d\n", max2( 1, 2 ) );
    return 0;
}

對應的匯編代碼為:

; int __cdecl max1( int a, int b )
00401000 MOV EAX,DWORD PTR SS:[ESP+4]
00401004 MOV ECX,DWORD PTR SS:[ESP+8]
00401008 CMP EAX,ECX
0040100A JG SHORT CppTest.0040100E
0040100C MOV EAX,ECX
0040100E RETN

; int __stdcall max2( int a, int b )
00401010 MOV EAX,DWORD PTR SS:[ESP+4]
00401014 MOV ECX,DWORD PTR SS:[ESP+8]
00401018 CMP EAX,ECX
0040101A JG SHORT CppTest.0040101E
0040101C MOV EAX,ECX
0040101E RETN 8 ; 被調用者的堆棧修正

; max1( 1, 2 )
00401030 PUSH 2
00401032 PUSH 1
00401034 CALL CppTest.00401000
00401039 ADD ESP,8 ; 調用者的堆棧修正

; max2( 1, 2 )
0040104A PUSH 2
0040104C PUSH 1
0040104E CALL CppTest.00401010

好了,我來簡要介紹一下。函數參數傳入函數體是借由堆棧段完成的,也就是將各個參數依某種次序推入SS中——在cdecl與stdcall約定中,這個次序都是自右而左的。另外,由于將參數推入了堆棧致使堆棧指針ESP發生了變化,所以要在函數結束的時候重新修正ESP。從上邊的匯編代碼中你也可以很清楚地看到,cdecl約定是在調用max1之后修正的ESP,而stdcall約定則是在max2返回時借由RETN 8完成了這個修正工作。

另外,從上邊的匯編代碼中還可以看到,函數的返回值是由EAX帶回的。

庖丁解牛

在了解了以上的知識后,我們就可以使用調試器來調試那個未知的DLL了。可以說,這整個的調試過程充滿了驚險和刺激,而且我們還需要一定的技巧——如果你像我一樣不喜歡閱讀匯編代碼的話。

在本文中,我所選擇的調試示例是FTerm中附帶的ipsearcher.dll,它提供了對純真IP數據庫的查詢接口。下圖是用Dependency Walker對其分析的結果:

你可以看到,這里邊有兩個導出函數:LookupAddress和_GetAddress,那么我們可以按照返回值、調用約定、函數名、參數列表的順序將它們聲明如下:

? ? LookupAddress( ? );
? ? _GetAddress( ? );

是的,有太多的未知,下面李馬將要逐一地破解這些問號。

調試器不可能孤立地對DLL進行調試,我們所需要的應該是一個合適的EXE,這樣有助于我們的探究工作。在這里我選擇的EXE是我編寫的ipsearcher.exe,當然這可能會讓你認為我這篇文章的組織順序有問題——畢竟是我已經知道了這兩個導出函數之后(編寫了ipsearcher.exe)還要假裝成不知道的樣子來對ipsearcher.dll來進行探究,所以我決定在下文中不對ipsearcher.exe的代碼進行任何關注,而是直接進入到ipsearcher.dll的領空。

打開調試器,載入ipsearcher.exe。當ipsearcher.dll被裝載后,會引發一個訪問異常,可以忽略這個異常繼續調試。根據Dependency Walker的分析結果,在ipsearcher.dll的0x00001BB0和0x00001C40處各下一個斷點。現在在“IP地址”中輸入一個IP地址(這里以寒泉BBS的IP為例),點擊“查詢”,會發現指令跳入0x00001C40中(也就是_GetAddress),它的代碼如下:

10001C40 MOV EAX,DWORD PTR SS:[ESP+4] ; 一個參數
10001C44 PUSH ipsear_1.10009BE8
10001C49 PUSH EAX
10001C4A CALL ipsear_1.LookupAddress ; 兩個參數
10001C4F ADD ESP,8 ; LookupAddress是cdecl調用約定
10001C52 MOV EAX,ipsear_1.10009BE8
10001C57 RETN ; _GetAddress這廝也是cdecl調用約定

很短的幾行代碼,不過它已經可以提供這些信息了:

  • 從SS的使用來看,_GetAddress只帶有一個參數。
  • _GetAddress中調用了LookupAddress,后者帶有兩個參數。
  • 調用LookupAddress之后進行了堆棧修正,所以LookupAddress是cdecl調用約定。
  • _GetAddress返回時并未進行堆棧修正,所以_GetAddress也是cdecl調用約定。

于是,我們可以替換一下剛才的問號了:

? CDECL LookupAddress( ?, ? );
? CDECL _GetAddress( ? );

下面可以進行單步調試了,當代碼步至10001C44時,你會發現寄存器窗口發生了如下的變化:

“202.207.177.9”終于出現了,這樣一來我們可以繼續對問號進行替換了:

? CDECL LookupAddress( PCSTR, ? );
? CDECL _GetAddress( PCSTR );

現在繼續對代碼進行跟蹤,是進入LookupAddress的時候了。我們可以從先前_GetAddress的代碼中可以發現,這兩個導出函數一直在圍繞10009BE8這個地址做文章,那么我們就要在單步調試LookupAddress的同時關注這個地址的數據改變。幾步跟蹤之后,你會發現10009BE8開頭的8字節(兩個DWORD)數據發生了改變,變成了10009AB4和10009B1C。那么我們再轉向這兩個地址,會發現:

這樣一來就很清楚了,10009BE8是一個字符串指針的數組,它有兩個元素。也就是說,我們的函數聲明可以換成這樣:

? CDECL LookupAddress( PCSTR, PSTR* );
PSTR* CDECL _GetAddress( PCSTR );

接下來需要確定的就是LookupAddress的返回值了。縱觀LookupAddress的返回代碼,你會發現這樣的片斷:

; 片斷1
10001C0B XOR EAX,EAX
10001C0D POP ESI
10001C0E RETN
; 片斷2
10001C2B MOV EAX,1
10001C30 POP ESI
10001C31 RETN

也就是說,這個函數有兩個返回值:0或1。那么最后的真相終于大白于天下——

BOOL CDECL LookupAddress( PCSTR, PSTR* );
PSTR* CDECL _GetAddress( PCSTR );

GetProcAddress?

到此為止,這兩個函數的聲明終于讓我們找出來了。也許你會覺得這就夠了——接下來就是用typedef定義函數指針,然后使用LoadLibrary、GetProcAddress調用這些函數的事情了。

如果你真的這么認為的話,那我認為我有必要向你介紹這另外的一種方式。

首先請你建立一個名為ipsearcher.def的文件,然后在其中寫入如下內容:

LIBRARY "ipsearcher"

EXPORTS
LookupAddress @1
_GetAddress   @2

將文件保存后,進入到命令行模式下,輸入以下命令(前提是你擁有Visual Studio的附帶工具lib.exe并有正確的路徑指向。以Visual Studio 6.0為例,這個工具通常位于Microsoft Visual Studio\VC98\Bin下):

lib /def:ipsearcher.def

執行的結果有一個警告,不必理會。這時候我們會發現,lib為我們生成了一個ipsearcher.lib。

然后,我們繼續編寫ipsearcher.h文件,如下:

#ifndef IPSEARCHER_H
#define IPSEARCHER_H

#include <windows.h>

#pragma commentlib, "ipsearcher.lib" )

extern "C"
{

BOOL CDECL LookupAddress( PCSTR, PSTR* );

PSTR* CDECL _GetAddress( PCSTR );

};

#endif // IPSEARCHER_H

大功告成!這樣我們就為這個光禿禿的ipsearcher.dll做了一份SDK開發包,而不必再使用動態加載的方法了。

總結一下再

其實,探究一個DLL并非像我這里所講述的這么簡單。這項工作很可能需要閱讀大量的匯編代碼,了解DLL函數體的流程才能使真相大白于天下。另外,還不能排除有的DLL被加密、加殼、反跟蹤……也就是說對于ipsearcher.dll,那簡直就是我撿了個便宜來借花獻佛了。

posted on 2007-10-30 15:20 葉子 閱讀(2140) 評論(2)  編輯 收藏 引用 所屬分類: 技術研究

Feedback

# re: 調用未知DLL中的導出函數 2008-12-09 11:21 風君

我認為更好的方法是直接用IDA,裝反匯編成C語言的插件,找到要看的函數,直接F5~~  回復  更多評論   

# re: 調用未知DLL中的導出函數 2008-12-19 13:17 elva

有些函數是F5出不來的,如果函數比較復雜,也總不能全都F5吧。。小型的還可以。  回復  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区高清| 亚洲国产日韩在线一区模特| 欧美黄色视屏| 欧美激情a∨在线视频播放| 亚洲国产精品一区在线观看不卡| 在线视频欧美日韩| 日韩视频免费观看高清在线视频| 国产精品99久久不卡二区| 亚洲在线视频| 美女诱惑一区| 国产精品免费看久久久香蕉| 国产中文一区二区| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 亚洲欧洲精品一区二区| 好吊色欧美一区二区三区四区| 黄色精品免费| 亚洲国产精品专区久久| 亚洲欧美激情四射在线日| 久久亚洲综合色一区二区三区| 欧美视频一区二| 黄色一区二区在线| 亚洲一区二区三区免费观看| 午夜精品福利视频| 欧美国产精品一区| 亚洲永久字幕| 在线日本高清免费不卡| 久久精品亚洲一区二区三区浴池| 亚洲韩国日本中文字幕| 欧美视频一二三区| 欧美成人国产一区二区| 欧美中文日韩| 国产精品分类| 亚洲综合国产精品| 亚洲视频网站在线观看| 欲香欲色天天天综合和网| 久久精品人人做人人爽电影蜜月| 一区二区三区你懂的| 欧美色123| 欧美超级免费视 在线| 国产精品免费网站| 亚洲国产日日夜夜| 亚洲成色999久久网站| 亚洲免费一级电影| 正在播放亚洲一区| 99re视频这里只有精品| 亚洲第一在线综合网站| 亚洲欧美伊人| 国产亚洲欧美一区| 蜜桃伊人久久| 老妇喷水一区二区三区| 亚洲经典一区| 亚洲美女区一区| 亚洲欧美视频在线观看| 欧美成人国产一区二区| 亚洲看片免费| 麻豆国产va免费精品高清在线| 亚洲免费在线观看| 午夜精品影院在线观看| 狠狠色噜噜狠狠色综合久| 亚洲欧美卡通另类91av| 性视频1819p久久| 久久国产精品99久久久久久老狼| 国产综合亚洲精品一区二| 亚洲欧美日韩高清| 欧美一级片在线播放| 国产美女精品免费电影| 久久九九久精品国产免费直播| 国产精品一区三区| 亚洲欧美日韩国产另类专区| 午夜免费日韩视频| 国产精品无人区| 欧美激情国产高清| 欧美日韩视频免费播放| 久久亚洲春色中文字幕久久久| 欧美91福利在线观看| 性娇小13――14欧美| 国产精品嫩草99a| 亚洲你懂的在线视频| 午夜欧美不卡精品aaaaa| 国产欧美日韩| 亚洲老板91色精品久久| 国产视频一区在线观看| 亚洲国产精品精华液2区45| 亚洲伦理一区| 欧美日韩一区在线观看视频| 亚洲一级片在线看| 亚洲精品久久久一区二区三区| 亚洲欧美日韩在线不卡| 久久久久久91香蕉国产| 亚洲国产精品久久久久秋霞不卡| 欧美大成色www永久网站婷| 日韩视频不卡中文| 久久精品视频在线看| 91久久国产自产拍夜夜嗨| 99热精品在线观看| 亚洲激情第一页| 欧美日韩美女一区二区| 香蕉久久夜色精品国产| 亚洲国产三级网| 性欧美大战久久久久久久久| 在线观看福利一区| 欧美日韩亚洲激情| 久久久久久久国产| 久久久久九九九| 亚洲精品欧美日韩专区| 国产九色精品成人porny| 免费亚洲视频| 亚洲综合首页| 亚洲三级免费| 日韩亚洲欧美一区| 欧美国产激情| 午夜精品久久久久久99热| 最新日韩av| 六月天综合网| 亚洲第一精品夜夜躁人人爽| 国产精品av免费在线观看| 亚洲免费激情| 欧美成人一区二区三区在线观看| 亚洲综合国产| 在线视频一区二区| 麻豆久久婷婷| 国产精品色午夜在线观看| 久久久亚洲国产天美传媒修理工 | 久久综合伊人77777麻豆| 亚洲手机在线| 亚洲伦伦在线| 在线视频观看日韩| 国产亚洲精品综合一区91| 国产精品久久久久久久久久ktv| 美女脱光内衣内裤视频久久影院 | 中文在线一区| 99在线|亚洲一区二区| 欧美激情一区二区三区在线| 久久深夜福利免费观看| 娇妻被交换粗又大又硬视频欧美| 欧美午夜精品久久久久久孕妇 | 欧美在线视频一区二区三区| 亚洲一区二三| 在线亚洲自拍| 亚洲一区二区三区四区在线观看 | 久久激情五月激情| 亚洲欧美中文另类| 午夜老司机精品| 亚洲一区二区三区在线播放| 亚洲图片欧美一区| 亚洲手机视频| 亚洲欧美日韩高清| 午夜视频一区二区| 性欧美大战久久久久久久久| 欧美一区二区三区四区夜夜大片 | 午夜精品久久久久| 午夜一区不卡| 久久精品99国产精品酒店日本| 欧美一区国产一区| 亚洲啪啪91| 99国产精品久久久久久久| 亚洲视频一区二区在线观看| 中日韩男男gay无套| 亚洲免费在线观看| 久久久精品动漫| 亚洲成人在线网| 午夜精品国产精品大乳美女| 欧美在线观看一二区| 久久久久久久久岛国免费| 免费亚洲电影在线| 亚洲精品一区二区三区99| 亚洲天堂av在线免费| 欧美在现视频| 欧美激情第三页| 国产精品欧美日韩一区| 在线成人小视频| 一区二区欧美日韩视频| 性欧美暴力猛交另类hd| 另类av导航| 99精品视频免费全部在线| 午夜宅男欧美| 欧美紧缚bdsm在线视频| 久久精品国产亚洲一区二区三区| 亚洲尤物视频网| 快播亚洲色图| 国产精品成人一区二区| 激情亚洲一区二区三区四区| 99精品热视频| 久久久www| 日韩视频一区二区三区在线播放| 欧美一区二区三区日韩视频| 欧美精品97| 亚洲欧美日韩成人| 午夜精品久久久久久99热| 蜜桃伊人久久| 国产目拍亚洲精品99久久精品| 亚洲国产老妈| 久久国产精品一区二区三区四区| 亚洲黄一区二区三区| 性久久久久久久| 欧美午夜精品久久久久久孕妇| 91久久综合| 免费观看成人www动漫视频| 亚洲在线中文字幕| 欧美日产国产成人免费图片|