如何通過編譯器反匯編
Ⅰ 如何將.o文件反匯編成.C文件
想得美,反匯編一般是將可執行文件反匯編成匯編文件~
因為編譯器的各種優化什麼的,編譯器的編譯過程是一個完全不可逆的過程,而相對來說,匯編器的行為就簡單不少,也是反匯編所做的事情...
Ⅱ 先生們,女神們,快來看啊…… 請問下,c語言通過編譯器轉換成匯編語言,那電腦是怎樣聽懂匯編語言呢說
1、比如彈出光碟機,學過高中物理應該知道電生磁,實際上就是個發動機,將電能轉換成機械能。
2、要弄懂這個問題,舉個 ia32 windows平台上的例子,我也只能大體上說一下,具體的細節在這里是說不完的。。以c++源碼
int main()
{
int a = 2;為例
}
經過編譯器,會生成匯編代碼:mov dword ptr ss:[esp-4], 2,匯編指令經過匯編器(即將匯編指令轉換成機器碼的程序)即C74424FC02000000這樣的機器碼,匯編指令生成的機器碼是有一定的指令格式的,你可以參考intel開發手冊,第一部分就有intel指令的格式。然後鏈接器根據生成的二進制文件,按照pe結構,生成一個exe文件。當你雙擊運行這個文件的時候,windows的pe loader 程序會將exe文件內存文件映射到虛擬內存中(即windows上的頁文件,也就是c盤中的pagefile文件),CPU的內部有一個震盪器(震盪器的原理很簡單,平時看到的電鈴就是這個原理),震盪器不斷的發送脈沖,每一次當脈沖為1時,CPU就會從內存中讀取指令,脈沖為1的時候,會根據內存中的地址匯流排,發送要取指的內存地址,這時候有一個解碼器,所謂的解碼器就是一種開關電路,比如有三個開關,當2個斷開1個閉合時,就表示成001,也就是取第一個單元的數據,這樣CPU將指令取得後,它會對指令進行解碼,解碼完後設置電路開關,然後將相應的數據放入到運算器中,運算器的實現,最早就是一個加法器。然後就是指令執行,執行完了,繼續取下一條指令。這就是存儲程序原理。
沒事歡迎來0x30網路貼吧,分享交流更多計算機編程知識。
Ⅲ VC++ 如何將c語言,變成匯編語言
可以直接用IDA反匯編VC用C生成的.exe文件,這個是專業的結構清晰。要用VC也行,不過裡面含有調試信息不實純粹的匯編,如果你的C語言已經通
過,能編譯成功,按F10就進入調試界面,然後點擊「調試」小窗口下面一行的Disassembly就可以看到匯編的代碼了
Ⅳ 反編譯exe文件就是把exe還原為匯編
首先了解一下概念,exe程序只是WIN下PE格式的可執行文件的一種,而所謂的計算機執行的代碼只是一串
二進制數
,跟數據沒區別,當CS,EIP指向哪,哪裡就是程序,而匯編語言之所以叫最底層的語言,是因為,
匯編的每一個語法,都應對了一串二進制的指令,這也就是
反匯編
的原理,所以
NO1.一、
反編譯
exe程序
就是
把
exe
還原為匯編語言嗎?,這句話,不能叫還原,應該叫解釋,「解釋」的東西,沒還原的那麼逼真,比如,在匯編
源程序
中所有的標號和注釋,進行編譯後,變成二進制可執行文件後,在反匯編,標號就變成數字了,而注釋更是沒了.....
二、除了
還原為
匯編語言,還能
反編譯為
其他
高級語言
嗎?不能,高級語言的語法是建立在大量的計算機
二進制代碼
之上的,比如你C語言隨便調用一個子函數,到了二進制中,他是先壓棧,參數(編譯後參數從右往左壓,每個語言還不一樣),然後就是call
子函數,子函數運行後,他還要清理堆棧,所以你一個句簡單的高級語言,其實蘊含了大量的代碼,而高級語言編譯後的程序,就脫離了他的開發環境,樓上說的會引起你誤會,java的中間碼,可以用他自帶的反編譯工具,因為Java不是
編譯器
,而是
解釋器
,所以他不編譯,只是解釋他的中間碼
NO2.所有的exe都可以反匯編,但是你要注意,不只exe這種pe格式,linux下可執行文件是elf,所以你在反匯編的時候,要注意可執行文件的文件的頭,而早期的DOS只是純二進制代碼,沒有
頭文件
,這個很重要,你要反匯編什麼格式,就要選擇相應的工具
NO3
.exe反匯編,當然是OD,不過,我對OD不熟悉,好像他只支持WIN下的反匯編
Ⅳ 如何反匯編獲知dll中函數的參數
可以通過反匯編來知道介面函數的參數,建議使用W32DSM來分析,也可以直接使用VC來分析,就是麻煩一點。
現在使用W32DSM來具體說明:
1。先打開需要分析的DLL,然後通過菜單功能-》出口來找到需要分析的函數,雙擊就可以了。
它可以直接定位到該函數。
2。看準該函數的入口,一般函數是以以下代碼作為入口點的。
push ebp
mov ebp, esp
3。然後往下找到該函數的出口,一般函數出口有以下語句。
ret xxxx;//其中xxxx就是函數差數的所有的位元組數,為4的倍數,xxxx除以4得到的結果
就是參數的個數。
其中參數存放的地方:
ebp+08 //第一個參數
ebp+0C //第二個參數
ebp+10 //第三個參數
ebp+14 //第四個參數
ebp+18 //第五個參數
ebp+1C //第六個參數
。。。。
-------------------------------------------
還有一種經常看到的調用方式:
sub esp,xxxx //開頭部分
//函數的內容
。。。
//函數的內容
add esp,xxxx
ret //結尾部分
其中xxxx/4的結果也是參數的個數。
-------------------------------------------------
還有一種調用方式:
有於該函數比較簡單,沒有參數的壓棧過程,
裡面的
esp+04就是第一個參數
esp+08就是第二個參數
。。。
esp+xx就是第xx/4個參數
你說看到的xx的最大數除以4後的結果,就是該函數所傳遞的參數的個數。
----------------------------------------------
到現在位置,你應該能很清楚的看到了傳遞的參數的個數。至於傳遞的是些什麼內容,還需要進一步的分析。
最方便的辦法就是先找到是什麼軟體在調用此函數,然後通過調試的技術,找到該函數被調用的地方。一般都是PUSH指令
來實現參數的傳遞的。這時可以看一下具體是什麼東西被壓入堆棧了,一般來說,如果參數是整數,一看就可以知道了,
如果是字元串的話也是比較簡單的,只要到那個地址上面去看一下就可以了。
如果傳遞的結構的話,沒有很方便的辦法解決,就是讀懂該匯編就可以了。對於以上的分析,本人只其到了拋磚引玉,
希望對大家有點用處。
昨天已經簡單的告訴大家,怎麼知道介面的參數個數了,以及簡單的介面。由於編譯器的優化原因,
可能有的參數沒有我前面說的那麼簡單,今天就讓我再來分析一下的DLL的調用的介面。如果在該DLL的
某個函數中,有關於API調用的話,並且調用API的參數整好有一個或多個是該DLL函數的參數的話。
那麼就可以很容易的知道該DLL函數的參數了。
舉例說明:以下匯編代碼通過W32DSM得到。
Exported fn(): myTestFunction - Ord:0001h
:10001010 8B442410 mov eax, dword ptr [esp+10]
:10001014 56 push esi
:10001015 8B74240C mov esi, dword ptr [esp+0C]
:10001019 0FAF742410 imul esi, dword ptr [esp+10]
:1000101E 85C0 test eax, eax
:10001020 7414 je 10001036
:10001022 8B442418 mov eax, dword ptr [esp+18]
:10001026 8B4C2408 mov ecx, dword ptr [esp+08]
:1000102A 6A63 push 00000000
:1000102C 50 push eax
:1000102D 51 push ecx
:1000102E 6A00 push 00000000
* Reference T USER32.MessageBoxA, Ord:01BEh
|
:10001030 FF15B0400010 Call dword ptr [100040B0]
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001020(C)
|
:10001036 8BC6 mov eax, esi
:10001038 5E pop esi
:10001039 C3 ret
-------------------------------------------------------
其中myTestFunction是需要分析的函數,它的裡面調用了USER32.MessageBoxA
這個函數計算參數個數的時候要注意了,它不是0X18/4的結果,原因是程序入口
的第二條語句又PUSH了一下,PUSH之前的ESP+10就是第4個參數,就是0x10/4 =4
PUSH之後的語句ESP+ XX,
其中(XX-4)/4才對應於第幾個參數。
ESP+0C ==第2個參數
ESP+10 ==第3個參數
ESP+18 ==第5個參數
ESP+08 ==第1個參數
----------------------------這樣共計算出參數的個數是5個,注意PUSH esi之前與PUSH esi之後,
PUSH一下,ESP的值就減了4,特別需要注意的地方!!!然後看函數的返回處RET指令,
由於看到了RET之前給EAX賦了值,所以可以知道該函數就必定返回了一個值,大家都知道EAX的寄存器
是4個位元組的,我們就把它用long來代替好了,現在函數的基本介面已經可以出來了,
long myTestFunction(long p1,long p2,long p3,long p4,long p5);
但是具體的參數類型還需調整,如果該函數裡面沒有用到任何一個參數的話。那麼參數
多少於參數的類型就無所謂了。一般來說這是不太會遇到的。那麼,我們怎麼去得到該函數的
參數呢?請看下面分析:
你有沒有看到* Reference T USER32.MessageBoxA, Ord:01BEh這一條語句,
這說明了,在它的內部使用了WINAPI::MessageBox函數,我們先看一下它的定義:
int MessageBox(
HWND hWnd, // handle of owner window
LPCTSTR lpText, // address of text in message box
LPCTSTR lpCaption, // address of title of message box
UINT uType // style of message box
);
它有4個參數。一般我們知道調用API函數的參數是從右往左壓入堆棧的,把它的調用過程
翻譯為偽ASM就是:
PUSH uType
PUSH lpCaption
PUSH lpText
PUSH hWnd
CALL MessageBox
---------------------------------------
我們把這個於上面的語句對應一下,就可以清楚的知道
hWnd = NULL(0)
lpText = ecx
lpCaption = eax
uType = MB_OK(0)
---------------------------------
在往上面看,
原來 EAX 中的值是ESP+18中的內容得到了
ECX 中的值是ESP+08中的內容得到了
那麼到現在為止就可以知道
lpText = ECX = [ESP+08] ==第1個參數
lpCaption = EAX = [ESP+18] ==第5個參數
現在我們可以把該DLL函數介面進一步寫成:
long myTestFunction(LPCTSTR lpText,long p2,long p3,long p4,LPCTSTR lpCaption);
至於第3個參數ESP+10,然後找到該參數使用的地方,imul esi, dword ptr [esp+10]有這么一條指令。
因為imul是乘法指令,我們可以肯定是把ESP+10假設位long是不會錯的,同理可以知道第2個參數esp+0C
肯定用long也不會錯了,至於第4個參數,它只起到了一個測試的作用,
mov eax, dword ptr [esp+10]
test eax, eax
je 10001036
看到這個參數的用法了嗎?
把它翻譯位C語言就是:
if(p3)
{
//做je 10001036下面的那些指令
}
return ;
到現在為止可以把第3個參數看成是個指針了吧!就是如果p3為空就直接返回,如果不空就做其它一下事情。
好了,到現在位置可以把正確的介面給列出來了:
long myTestFunction(LPCTSTR lpText,long n1,char *pIsNull,long n2,LPCTSTR lpCaption);
哈哈,現在成功了!!!
long CryptExtOpenCER(long p1,long p2,LPCSTR p3,long p4);
其中第3個參數可能是文件名稱,
或者是PCERT_BLOB
它有CERT_QUERY_OBJECT_FILE,或者是CERT_QUERY_OBJECT_BLOB來決定。
---------------------------------------------------------------
今天想到了一個很好的辦法,來解決參數的問題,不過有一定難度。
1。根據以前講的各種方法,可以很快速的知道參數的個數,假設該函數
名稱為MyTestFunc,參數的個數為3個。
於是可以定義如下:
long MyTestFunc(long p1,long p2,long p3);
2。安裝一個HOOK(DLL)
3。通過別的程序調用,觸發HOOK,調試到HOOK裡面,就可以很清楚的知道
調用的參數,數值。
-------------
此方法本人還沒有去實現,相信肯定是可以的。這樣得到的參數應該相當准確。
Ⅵ re從零開始的反編譯教程
寫在開頭,引用很喜歡的一句話: 要麼學!要麼不學!學和不學之間沒有中間值 不學就放棄,學就要去認真的學! --致選擇
為了回溯編譯過程(或對程序進行逆向工程),我們使用各種工具來撤銷匯編和編譯過程,這些工具就叫反匯編器和反編譯器。反匯編器撤銷匯編過程,因此我們可以得到匯編語言形式的輸出結果。反編譯器則以匯編語言甚至是機器語言為輸入,其輸出結果為高級語言。
數組的表示方式是:在基本類型前加上前中括弧「[」,例如int數組和float數組分別表示為:[I、[F;對象的表示則以L作為開頭,格式是 LpackageName/objectName;
(注意必須有個分號跟在最後),例如String對象在smali中為: Ljava/lang/String; ,其中 java/lang 對應 java.lang 包,String就是定義在該包中的一個對象。或許有人問,既然類是用 LpackageName/objectName; 來表示,那類裡面的內部類又如何在smali中引用呢?
答案是:在 LpackageName/objectName/subObjectName 的 subObjectName 前加 $ 符號。
方法的定義一般為: Func-Name (Para-Type1Para-Type2Para-Type3...)Return-Type
注意參數與參數之間沒有任何分隔符,同樣舉幾個例子就容易明白
無序列表的使用,在符號"-"後加空格使用。如下:
https://www.jianshu.com/p/1c54c1ccf5cc
https://www.cnblogs.com/onelikeone/p/7594177.html
解決:點擊進去jd-gui,刪除試一試。再不行換最新版本
解析結束後進行編譯報錯
解決方法: https://blog.csdn.net/fuchaosz/article/details/104800802
Failed parse ring installPackageLI: Targeting R+ (version 30 and above) requires the resources.arsc of installed APKs to be stored uncompress
解決方法:
降低gradle里版本,若出現
signatures do not match the previously installed version; ,
使用adb install命令在手機上安裝app時,遇到這個報錯。原因是新裝的app和手機上現有的舊版app沖突了。
解決方法:刪除手機上原來的app,再重新安裝即可。
可是轉念一想如果反編譯的apk都是Version 30 R+以上,難道我解壓後挨個改一遍gradle?太徹淡了,一定有解決方法,所以有了下面探究出現這個問題的解決方法:既然報錯是資源文件高版本不支持,而且沒有4位對齊,那麼不編譯資源文件就好了
APK簽名工具之jarsigner和apksigner:
https://blog.csdn.net/xzytl60937234/article/details/89088215?utm_medium=distribute.pc_relevant.none-task-blog-js_landingword-1&spm=1001.2101.3001.4242
利用apktool反編譯apk,並且重新簽名打包:
https://blog.csdn.net/qq_21007661/article/details/109851522?utm_medium=distribute.pc_relevant.none-task-blog-js_title-4&spm=1001.2101.3001.4242
驗證apktool能否使用
apktool -r d apk名字.apk,不反編譯資源文件,為什麼這么做,先挖個坑
錯誤提示沒有4位對齊和不支持30版本以上的資源文件。所有嘗試不編譯資源文件
解決4位對齊的方法:
查看當前目錄,生成了新文件:abc.keystor
使用JarSigner對apk進行簽名,命令如下
jarsigner -verbose -keystore abc.keystore -signedjar testx.apk src.apk abc.keystore
直接反編譯的apk產生上述錯誤
但是只編譯資源文件的apk安裝時
發現沒有使用V2進行簽名,這時候進行V2簽名, (apksigner,默認同時使用V1和V2簽名 )
所以先對只編譯資源文件的apk進行V2嘗試看能否成功
重復1(進行apktool -r d apk名字.apk)-->2 -->3 -->4( 不使用jarsigner而使用apksigner )
將生成的abc.keystore和打包回的apk( apktoolapp-debugdist 里的app-debug.apk)放入 C:Users aowei.lianAppDataLocalAndroidSdkuild-tools30.0.3 下,因為Android studio的SDK下有apksigner.bat.
對jarsigner只是apk進行了V1簽名;在Android7.0引入了V2簽名,因此,當進入sdk25.0.0及後續版本,會發現一個apksigner.bat執行腳本。
我們可以通過apksigner進行V2簽名,當然,apksigner默認是同時支持V1與V2的,於是:
學習了公鑰和密鑰的使用和區別,使用私鑰的加密演算法稱為對稱加密演算法,這種演算法實現是接收方和發送方公用一道密鑰,優點是效率高,缺點是安全性差,如果被第三人得知密鑰則信息泄露,由此衍生了公鑰加密演算法,也就是非對稱加密演算法,這個演算法是接收方給發送方公鑰,發送方用公鑰加密後發給接收方,接受方再用私鑰解密。這樣即使所有人知道公鑰也不會造成信息泄露。缺點是效率非常低。
此外了解了RSA簽名的大致過程,發送方擁有公鑰和私鑰,對信息進行摘要然後把摘要通過密鑰進行簽名,然後把簽名和信息一起發出去,那麼如何驗證該信息就是發送方發出的呢,這時候就使用到了公鑰驗證,通過公鑰對信息進行解簽,然後使用一樣的摘要演算法得到摘要,如果得到的摘要和解簽後的內容一致則說明是發送方發出。
總結就是公鑰加密,私鑰解密。公鑰驗證,私鑰簽名
RSA 密碼體制是一種公鑰密碼體制,公鑰公開,私鑰保密,它的加密解密演算法是公開的。由公鑰加密的內容可以並且只能由私鑰進行解密,而由私鑰加密的內容可以並且只能由公鑰進行解密。也就是說,RSA 的這一對公鑰、私鑰都可以用來加密和解密,並且一方加密的內容可以由並且只能由對方進行解密。
因為公鑰是公開的,任何公鑰持有者都可以將想要發送給私鑰持有者的信息進行加密後發送,而這個信息只有私鑰持有者才能解密。
它和加密有什麼區別呢?因為公鑰是公開的,所以任何持有公鑰的人都能解密私鑰加密過的密文,所以這個過程並不能保證消息的安全性,但是它卻能保證消息來源的准確性和不可否認性,也就是說,如果使用公鑰能正常解密某一個密文,那麼就能證明這段密文一定是由私鑰持有者發布的,而不是其他第三方發布的,並且私鑰持有者不能否認他曾經發布過該消息。故此將該過程稱為「簽名」。
Android 簽名機制 v1、v2、v3
進入JDK/bin, 輸入命令
參數:
進入Android SDK/build-tools/SDK版本, 輸入命令
參數:
例如:
最後安裝加 -t :
附上參考鏈接:
https://blog.csdn.net/A807296772/article/details/102298970
配置NDK的時候如果按鈕是灰色的,手動配置
直接在javac後面指定編碼是UTF-8就是了。
需要注意的是要加上* -classpath .其中classpath後面的一個黑點是不能省略的。
編譯好後如何導入so庫
成功運行後發現lib目錄下已經apk編進去so了
https://www.52pojie.cn/thread-732298-1-1.html
本節所有到的工具和Demo
IDA
鏈接: https://pan..com/s/15uCX8o6tTSSelgG_RN7kBQ
Demo
鏈接: https://pan..com/s/1vKC1SevvHfeI7f0d2c6IqQ
找到so並打開它 因為我的機型是支持arm的所以我這里打開的是armeabi文件夾下的so 如果機型是x86模式的那麼這里要打開x86模式下的libJniTest.so
編譯過程:
按住鍵盤組合鍵 shift + f12 打開字元串窗口 這個窗口將會列舉出so中所包含的所有字元串 因為上節課我們只編寫了一個字元串 所以這里只有一個hello 52pojie! 如果打開的是x86的so這里還會有一些.so 但是字元串只有這一個
滑鼠點在hello 52pojie!字元串上,打開 Hex mp窗口,修改hello 52pojie!對應內存地址的內容
關於字元對應的16進制可以在網路搜索ascii碼表 找到字元所對應的16進制
因為我要把hello 52pojie!修改成hello world! 是不是只要找到每個字元所對應的hex修改就好了
這里我看到 hello 52pojie!對應的hex是:68 65 6C 6C 6F 20 35 32 70 6F 6A 69 65 21
我在ascii碼表上找到world所對應的十六進制是:77 6F 72 6C 64
所以hello world! 對應的十六進制是:68 65 6C 6C 6F 20 77 6F 72 6C 64 21
注意編輯的時候游標暫停的位置只有先輸入字母才能更改成功,修改好後 右鍵Apply changes應用
退出後保存
此時已經so修改完畢
大功告成,hello 52pojie! --> hello world!
Ⅶ 反編譯exe文件就是把exe還原為匯編
NO1. 反編譯exe程序 就是 把 exe 還原為匯編語言嗎? 除了 還原為 匯編語言,還能 反編譯為 其他高級語言嗎? 比如 c c++ java 等.
1. 簡單的說就是用工具打開exe文件會出現匯編代碼。不能。這是反匯編的工作就是看著匯編代碼用別的語言來實現。
NO2. 是不是所有exe 程序 都 可以 反編譯 為 匯編語言?
2. 理論上說是的,不過有的程序加了殼,這樣就要先脫殼這是破解的知識,他們為了保護自己的軟體防止盜版。
(不是多有的exe都能用od打開的,你可以看看破解的相關知識。去看雪就行)
NO3. 推薦一款 把 exe 程序 反編譯為 匯編語言 的 軟體。 要求 兼容 windows vista home basic 本人是 有一丁點 匯編基礎 的 菜鳥,,希望高手 不吝指教。
3. 上網搜 OD 反匯編工具是很強大的 我的win7沒有問題。還有一款比較nb的是IDA你還是不要去碰它了,牛人用的。
Ⅷ 請教keil如何將hex文件反匯編
新建擾燃一個工程文粗者件,然後新建一個空的ASM文件。做這步只是為了能進入模擬。然後找到反匯編窗口,右鍵——載入HEX或目標文緩凳虛件,裡面就是反匯編代碼了
Ⅸ 如何:使用「反匯編」窗口
默認情況下隱藏只有在「選項」對話框中的「調試」節點下啟用了地址級調試後,該功能才可用。
但對於腳本或
SQL
調試是不可用的。
「
反匯編
」窗口顯示與
編譯器
所創建的指令對應的匯編代碼。
如果正在調試
託管代碼
,則這些
匯編指令
對應於由實時
(JIT)
編譯器創建的本機代碼,而不是由
Visual
Studio
編譯器生成的
Microsoft
中間語言
(MSIL)。
除匯編指令外,
「反匯編」窗口還可顯示如下可選信息:
每條指令所在的
內存地址
對於本機應用程序,這是實際內存地址。
對於
Visual
Basic、C#
或託管代碼,這是距離函數開頭的偏移量。
程序集
代碼派生於的源代碼。
代碼位元組
—
實際計算機或
MSIL
指令的位元組表示形式。
內存地址的符號名。
對應於源代碼的行號。
匯編語言指令由
助記符
(指令名稱的縮寫)和代表變數、寄存器以及常量的符號所組成。
每一條
機器語言
指令由一個匯編語言助記符代表,通常其後還跟有一個或多個變數、寄存器或常量。
如果您無法閱讀匯編語言但又想充分利用「反匯編」窗口,請參考有關匯編語言編程的好書。
匯編語言編程超出了我們對「反匯編」窗口進行簡單介紹的討論范圍。
匯編語言代碼在很大程度上依賴處理器的寄存器(對託管代碼而言,依賴公共語言運行時寄存器),您將發現協同使用「反匯編」窗口和「寄存器」窗口將很有用,可以允許您檢查寄存器內容。
您很可能願意使用匯編語言,而從來不會願意或需要查看原始的、數字形式的
機器代碼
指令。
不過,如果願意的話,可以利用則埋歷孫搜「內存」窗口或從「液銀反匯編」窗口的
快捷菜單
中選取「代碼位元組」來查看。
注意顯示的對話框和菜單命令可能會與「幫助」中的描述不同,具體取決於您現用的設置或版本。
若要更改設置,請在「工具」菜單上選擇「導入和導出設置」。
有關更多信息,請參見使用設置。
Ⅹ dll文件如何反匯編成源碼,C++語言編寫
DLL 屬於可執行文件中的一類,又稱為動態鏈接庫,不能直接用DEBUG載入,一般由應用程序因使用該庫中的函數,而由操作系統在應用程序載入的同時被載入入特定地址,這個地址一般是DLL在鏈接時指定的。當DLL被載入到運行空間,根據輸出函數表,可以得到各個函數的入口地址,然後用DEBUG在各個入口下斷點,調用該函數時DEBUG將跟蹤進入該函數,從而實現反匯編。
反匯編屬於逆向工程,逆向工程的主要手段有兩大類,其中一類是動態分析,另一類是靜態分析。
前面提到的方法屬於動態分析,由DEBUG實現反匯編,該方法不容易得到完整的代碼,一般只能形成一段一段獨立分散的代碼,同時由於DEBUG的局限性,反匯編的代碼質量多不高,生成的代碼不能直接使用,原因在於DLL在載入時若沒有載入到指定地址空間,操作系統將對代碼進行重定向,所以DEBUG只能得到重定向後的代碼,這類代碼必須修改每一個重定向點,才能形成可執行代碼。作為WINDOWS32位操作系統, OLLYDBG是最為優秀的調試、跟蹤、反匯編工具,多窗口運行,可以方便的通過窗口操作完成各類動作,而不需要像一般DEBUG那樣由命令行來完成,OLLYDBG還有許多一般調試器不具備的功能,同時由於每一代高手不斷的修改,使其具有多種功能,同時帶來的就是混亂,誰也不知道有多少版本,誰也不清楚每個版本到底增加了什麼功能,但就這樣,也是瑕不掩疵, OLLYDBG任然是DEBUG中最強大,最好使用的。
靜態分析和動態分析不同,靜態分析直接打開原程序,載入而不運行,然後直接分析載入的代碼。目前靜態分析工具,最強大的當屬IDA,IDA支持幾乎所有種類的匯編語言。
IDA載入應用程序有許多選項,可以選擇完整的載入整個程序,也可以選擇載入程序的某個塊,一般可選擇的是否載入文件頭、資源表、輸入表、輸出表等等。
IDA還支持調試,也就是說,當你在進行反匯編過程時,可以直接使用IDA來調試跟蹤,以分析代碼的動態執行情況,不過就動態跟蹤來說,OLLYDBG更為強大。
IDA反匯編的正確率和代碼的復雜程度有關,對於正規開發的代碼,尤其是如果能夠獲得源程序的調試文件,即所謂的PDB文件,IDA可以讀取PDB文件中的信息,使得反匯編的效率和准確度大為提高,生成的代碼甚至比源代碼易讀。IDA將反匯編生成的結果存入IDB文件中。當你確認反匯編的結果達到你的要求,可以讓IDA輸出匯編源代碼,IDA也提供其他格式的輸出,例如HTML文件,便於用戶閱讀。樓主主要是用於分析DLL文件,一般來說這類文件更適合做靜態分析,所以推薦使用IDA來進行。
IDA對於分析那些加殼或含有大量花指令、混淆代碼、垃圾代碼的程序,反匯編的正確率會大為下降,因為IDA無法正確的確認當期位置上的數值是屬於代碼,還是屬於數據,是普通C字元,還是DELPHI的字元串,還是UNICODE字元串,是結構數據還是數組還是類表(DELPHI生成的代碼中含有大量的類表)等等。遇到這種情況,就需要使用者掌握許多技巧,例如可以通過使用者對當前數據的認識,指導IDA如何處理當前的數據。對於大批量的,具有某些規律的數據,IDA還提供了腳本語言(文件尾位idc),通過對腳本的執行來指導IDA如何進行反匯編。對於更為復雜的情況,例如程序是自解壓運行的,這時IDA就沒有任何能力來進行正確的分析,通常都會用OLLYDBG動態跟蹤,等程序完成自解壓後從內存中將解壓後的代碼完整的挖下來形成文件,再由IDA進行靜態分析。
對於成功進行反匯編的代碼,IDA根據代碼的入口、調用、轉移等指令,可以為使用者提供各種格式的程序的流程圖,IDA提供許多格式由用戶選擇,便於用戶理解程序的結構。
匯編語言的科學定義,其實就是介於機器碼(各種01)和高級語言(如C)之間的一種語言。你用C語言寫一段程序,其實要在機器上運行的話,機器是不懂的,要經過編譯器、匯編器編譯,變成匯編,最終再變成機器碼,機器根據這些機器碼的01可以控制硬體電路完成你程序想執行的操作。