日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

[系统安全] 六.逆向分析之条件语句和循环语句源码还原及流程控制

發(fā)布時間:2024/6/1 windows 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [系统安全] 六.逆向分析之条件语句和循环语句源码还原及流程控制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

您可能之前看到過我寫的類似文章,為什么還要重復撰寫呢?只是想更好地幫助初學者了解病毒逆向分析和系統(tǒng)安全,更加成體系且不破壞之前的系列。因此,我重新開設了這個專欄,準備系統(tǒng)整理和深入學習系統(tǒng)安全、逆向分析和惡意代碼檢測,“系統(tǒng)安全”系列文章會更加聚焦,更加系統(tǒng),更加深入,也是作者的慢慢成長史。換專業(yè)確實挺難的,逆向分析也是塊硬骨頭,但我也試試,看看自己未來四年究竟能將它學到什么程度,漫漫長征路,偏向虎山行。享受過程,一起加油~

系統(tǒng)安全系列作者將深入研究惡意樣本分析、逆向分析、攻防實戰(zhàn)和Windows漏洞利用等,通過在線筆記和實踐操作的形式分享與博友們學習,希望能與您一起進步。前文介紹了OllyDbg和Cheat Engine工具逆向分析用法,完成植物大戰(zhàn)僵尸的游戲輔助器,包括修改陽光值和自動拾取陽光兩個功能。這篇文章將帶領大家來學習科銳錢林松老師的視頻,詳細講解條件語句和循環(huán)語句源碼還原及流程控制逆向。希望對入門的同學有幫助。

話不多說,讓我們開始新的征程吧!您的點贊、評論、收藏將是對我最大的支持,感恩安全路上一路前行,如果有寫得不好的地方,可以聯(lián)系我修改。基礎性文章,希望對您有所幫助,作者的目的是與安全人共同進步,加油~

文章目錄

  • 一.C++逆向條件結構基礎入門
    • 1.單分支結構分析
    • 2.雙分支結構分析
  • 二.C++逆向循環(huán)結構基礎入門
    • 1.do-while結構分析
    • 2.while結構分析
    • 3.for結構分析
  • 三.總結

作者的github資源:

  • 系統(tǒng)安全:https://github.com/eastmountyxz/SystemSecurity-ReverseAnalysis
  • 網(wǎng)絡安全:https://github.com/eastmountyxz/NetworkSecuritySelf-study

前文分析:

  • [系統(tǒng)安全] 一.什么是逆向分析、逆向分析基礎及經(jīng)典掃雷游戲逆向
  • [系統(tǒng)安全] 二.如何學好逆向分析及呂布傳游戲逆向案例
  • [系統(tǒng)安全] 三.IDA Pro反匯編工具初識及逆向工程解密實戰(zhàn)
  • [系統(tǒng)安全] 四.OllyDbg動態(tài)分析工具基礎用法及Crakeme逆向破解
  • [系統(tǒng)安全] 五.OllyDbg和Cheat Engine工具逆向分析植物大戰(zhàn)僵尸游戲
  • [系統(tǒng)安全] 六.逆向分析之條件語句和循環(huán)語句源碼還原及流程控制

聲明:本人堅決反對利用教學方法進行犯罪的行為,一切犯罪行為必將受到嚴懲,綠色網(wǎng)絡需要我們共同維護,更推薦大家了解它們背后的原理,更好地進行防護。


一.C++逆向條件結構基礎入門

大家寫過相關的算法嗎?
加密代碼中會涉及循環(huán)和分支,你要識別算法,首先就是需要將它的算法處理流程識別出來。當我們還原出等價的高級代碼之后,就沒有逆向分析人員的事情了,因為接下來涉及到密碼學、數(shù)學相關人員的工作,逆向人員把加密的代碼還原出來后就應該扔給研究密碼學的數(shù)學家,他們負責玩數(shù)學對抗,而逆向關注的是編譯原理和代碼還原。同時,逆向還涵蓋了識別對象、識別算法、識別優(yōu)化、識別虛函數(shù)對象的繼承關系等等,這里主要結合項目相關的加密和解密進行講解。接著作者準備穿插著VC++6.0和VS2019兩個版本進行講解。


1.單分支結構分析

第一步,通過VC++6.0編寫一個最簡單的程序,創(chuàng)建工程名稱為“RE_SF”。


運行結果如下圖所示,可以看到“Hello World”。


第二步,編寫單分支結構的相關代碼。

#include "stdafx.h"int main(int argc, char* argv[]) {if (argc > 8 ){printf("argc > 8\r\n");}return 0; }

接著選擇“Win32 Release”編譯運行代碼。


第三步,接著用OD軟件打開EXE文件。
此時創(chuàng)建的工程目錄分布如下圖所示。

OllyDbg打開之后顯示如下圖所示的界面,程序入口地址是0x00401051。

  • 程序入口:0x00401051


第四步,首先我們需要定位main函數(shù),其方法非常簡單,找到有三個PUSH的下面就是main函數(shù),因為main函數(shù)有三個參數(shù)(argc、argv[],、envp[])。接著按F2下斷點。

  • 主函數(shù):0x00401100

繼續(xù)按下F7跟進,會看到一個單分支結構。那么,單分支結構它有什么特點呢?

  • 進入主函數(shù):0x00401000


第五步,先給大家普及單分支語句的代碼定式基礎知識。
在高級語言中單分支代碼定式如下:

//程序語言 if(...) {... }//代碼定式 IF_BEGIN:jxx IF_END...IF_END:...

為什么需要記住這個代碼定式呢?
因為對于流程控制的識別,我們關鍵是要找到IF語句的作用域(上界和下界),上界在jxx的位置,稱之為IF_BEGIN。接著有個jxx條件跳轉,跳轉到目標且沒有其他的特征,這種就稱之為單分支的代碼定式。

回到我們的匯編代碼,拿到這個代碼之后,發(fā)現(xiàn)存在一個箭頭指向跳轉目標,這樣就出現(xiàn)了IF模塊的上界和下界,條件判斷作為IF的上界,條件跳轉的目標作為IF下界,通過這種套路方式來還原代碼。


第六步,分析嵌套的單分支語句。
假設我們的判斷中再嵌套一層或增加一個分支,又該怎么判斷呢?對于我們還原代碼的人來說,不用管它,你把上下界圈出來,然后遞歸解決。所有流程問題只要找到上下界,剩下的問題就變成了順序結構,再看著代碼一條條還原即可。

#include "stdafx.h" #include <stdlib.h>int main(int argc, char* argv[]) {if (argc > 8 ){printf("argc > 8\r\n");if (argc < 80){printf("argc < 80\r\n");}}system("pause");return 0; }

接著運行程序生成新的EXE程序,然后通過OD軟件打開分析,給主函數(shù)下個斷點然后進入主函數(shù)顯示如下圖所示的界面。

  • 主函數(shù)內容:0x00401000


第七步,同樣的方法將兩層單分支語句的上下界圈出來。
我們發(fā)現(xiàn)這兩個判斷的下界重合了,都是跳轉到0x00401029位置,這就明顯是個嵌套。

總結下IF語句的特點:

  • 觀察它的條件跳(上下界)
  • 條件跳的目標上面的代碼沒有其他特征,即“ADD ESP, 4"

那么,怎么還原出高級代碼呢?


第八步,通過匯編代碼還原出高級代碼。
還原代碼需要進行反條節(jié)操作,并且學會查詢相關指令。比如JLE、JGE是什么意思呢?

  • JLE(jump if less or equal,or not greater):匯編語言中的條件轉移指令,小于或等于則條件轉移
  • JGE:大于或等于轉移指令

注意,在還原的時候需要做反條件操作。那么,什么叫反條件呢?具體解釋如下:

  • JLE:小于等于跳轉 --> 代碼還原就是“不小于等于”,即:大于跳轉
  • JGE:大于等于跳轉 --> 代碼還原就是“不大于等于”,即:小于跳轉

反條件
因為當我們滿足這個條件的時候它會跳轉到另一個地方(結束地方),它沒有執(zhí)行具體的代碼;所以如果我們想要執(zhí)行模塊中的代碼,就需要反條件處理。即匯編的語義和高級語言的語義是反的,高級語言的語義是滿足條件則執(zhí)行語句塊,而匯編的語義是滿足條件不執(zhí)行語句塊。

接著我們繼續(xù)看觸發(fā)跳轉的代碼,它是通過CMP比較來觸發(fā)的。

  • CMP ESI, 8
    ESI是通過參數(shù)傳遞過來的,然后和8進行不小于等于的比較
  • CMP ESI, 50
    ESI和50進行不大于等于的比較

此時,我們再將單分支步驟簡單歸納如下:

  • (1) 通過反匯編代碼序列,匹配代碼定式;
  • (2) 如果是單分支if結果,則將條件轉義指令jxx做反條件還原

第九步,接著我們換個工具用VS2019打開我們的代碼,生成新的Release版本。

然后刪除本地的Release資源,生成一個新的Release方案。


第十步,用IDA Pro打開可執(zhí)行EXE程序進行分析。
同樣,使用IDA也是可以進行逆向分析的,打開新生成的逆向分析工具如下所示。

右鍵選擇“Text View”查看源代碼。

找到main函數(shù),然后點擊“_main”位置高亮顯示。

按下“N”鍵可以對函數(shù)進行重命名,如下圖所示。

注意,前面分享的識別方法和編譯器版本、編程語言(C++、VB)等都沒有關系,它是編譯原理的問題。接著我們重點還是回歸到代碼上去,點擊“l(fā)oc_401039”函數(shù)高亮,同樣的方法劃分出這個單分支的上界和下界,并且嵌套了一個單分支,最終還原出源代碼。

所以,不論使用VC++6.0或VS編譯工具,還是使用IDA或OD分析工具,它們還原代碼的原理及方法都是一樣的。在實際項目中,不論你用什么分析工具,最終能分析出結果就好。



2.雙分支結構分析

第一步,編寫雙分支代碼。


第二步,普及雙分支語句的代碼定式基礎知識。
在高級語言中雙分支代碼定式如下。該代碼序列關鍵是發(fā)現(xiàn)jxx后,需要檢查目標看看下面有沒有一個jmp指令,如果有個jmp且是往下跳的,if-else就成立了。

//程序語言 if(...) {... } else {... }//代碼定式 IF_BEGIN: jxx ELSE_BEGIN... IF_END:jmp ELSE_END ELSE_BEGIN:... ELSE_END:...

第三步,接著生成新的exe文件,用OD打開分析。
同樣的方法進入主函數(shù),然后F7單步步入0x00401000位置,如下圖所示。

核心代碼及其跳轉如下圖所示。

  • JLE --> 0x0040100E:PUSH操作
  • JMP --> 0x00401013:CALL操作

雙分支結構特點:

  • jxx的目標處上一行指令為jmp,而且是往高地址去的jmp(往下跳)。如果是循環(huán),后面會講到它可能往上跳。

確定上下界之后,生成如下圖所示的if模塊和else模塊,同樣的反條件處理還原代碼。

注意,這里有一個小小的優(yōu)化,編譯原理中的代碼外提。它是什么意思呢?
假設有個節(jié)點A,現(xiàn)在有了流程分支B1和B2,B1完成后執(zhí)行C,B2完成后也會執(zhí)行C。編譯器為了減小代碼的節(jié)點,因為代碼節(jié)點越多,代碼越長,就做了等價流程的代碼外提優(yōu)化,從而匯總到C,少了一個節(jié)點。

  • 編譯器會視情況減少節(jié)點的優(yōu)化
  • 編譯器也會增加節(jié)點來減小路徑的優(yōu)化


第四步,采用同樣的方法用IDA工具分析還原代碼,其效果也一樣。

接著你可能會疑問這兩個PUSH是干啥呢?**

  • push offset aArgc8 ; “argc > 8\r\n”
  • push offset aArgc8_0 ; “argc <= 8\r\n”

C語言中沒有標準的高級語法對應匯編中的PUSH操作,說明它有代碼優(yōu)化了,就是代碼外提操作。它們有個公共的函數(shù)調用被提到下面去了,就是下圖所示的兩行代碼,這個時候我們要把它放回去方便還原。

接著我們復制匯編代碼至C語言中進行還原,方便大家理解。代碼如下,此時增加了if和else的上下界,但發(fā)現(xiàn)兩個push無法還原。

同時將代碼外提部分分別放到if和else模塊中,就能實現(xiàn)最終代碼還原,如下圖所示。最后刪除掉多余的匯編注釋即可。

繼續(xù)還原條件判斷內容,JLE小于等于換成大于8就好。在真實環(huán)境中,還會遇到雙分支中有循環(huán)或條件嵌套的問題,不要擔心,找到上下界繼續(xù)分析即可。

#include "stdafx.h" #include <stdlib.h>int main(int argc, char* argv[]) {//.text:00401000 cmp [esp+argc], 8 //.text:00401005 jle short loc_40100Eif (argc > 8){ //.text:00401007 push offset aArgc8 ; "argc > 8\r\n" //.text:0040100C jmp short loc_401013 //.text:00401013 call sub_4010C6printf("argc > 8\r\n"); //.text:00401018 add esp, 4} //.text:0040100E ; --------------------------------------------------------------------------- //.text:0040100Eelse{ //.text:0040100E loc_40100E: ; CODE XREF: _main+5↑j //.text:0040100E push offset aArgc8_0 ; "argc <= 8\r\n" //.text:00401013 call sub_4010C6printf("argc <= 8\r\n"); //.text:00401018 add esp, 4} //.text:00401013 //.text:00401013 loc_401013: ; CODE XREF: _main+C↑j //.text:0040101B push offset aPause ; "pause"system("pause");return 0; }

二.C++逆向循環(huán)結構基礎入門

1.do-while結構分析

循環(huán)包括do-while、while和for三種,你會覺得哪一種消息最高呢?do-while是三種循環(huán)中效率最高的,由于其無條件先執(zhí)行一次,所以大家很少使用,但其效率很高。

基本語法
先執(zhí)行,再判斷。先執(zhí)行一遍循環(huán)操作,若符合條件,循環(huán)操作繼續(xù)執(zhí)行,否則退出循環(huán)。

do{循環(huán)操作語句; }whlie(循環(huán)條件);

第一步,我們編寫一個1加到100的循環(huán)代碼,這次直接使用Debug版本。

#include "stdafx.h" #include <stdlib.h>int main(int argc, char* argv[]) {int n = 1;int nSum = 0;//do-while 執(zhí)行一次do {nSum = nSum + n;n++;} while(n <= 100);printf("%d", nSum);system("pause");return 0; }

第二步,通過OD打開運行的EXE程序“RE_XH.exe”。

  • 程序入口地址:0x00401260


第三步,往下查找代碼,發(fā)現(xiàn)3個PUSH后(參數(shù))就是主函數(shù),然后F2添加斷點并F7步入主函數(shù)。

  • 主函數(shù):CALL RE_XH.00401005


第四步,分析匯編代碼。
這里存在一個JLE跳轉,如果條件跳往上跳就是do-while循環(huán)。

循環(huán)肯定會往上走,否則構成不了循環(huán),它需要反復執(zhí)行同一代碼段。如果跳轉的目標沒有檢查條件,就是do-while循環(huán)。簡單總結下識別do-while循環(huán)步驟:

  • 識別代碼定式
  • 如果是do循環(huán),則按jxx同條件還原等價高級代碼

注意,同條件的就只有do-while結構。在do-while循環(huán)中,它跟匯編的語義是一樣的,只有當條件滿足則流程更新到循環(huán)的起始地點,所以它是正條件還原。而前面的if-else判斷都是反條件

//程序語言 do {... }while(xxx);//代碼定式 DO_BEGIN:...jxx DO_BEGIN DO_END:...

2.while結構分析

基本語法
先判斷,再執(zhí)行。

whlie(循環(huán)條件){循環(huán)操作語句; }

第一步,我們編寫一個1加到100的循環(huán)代碼。

#include "stdafx.h" #include <stdlib.h>int main(int argc, char* argv[]) {int n = 1;int nSum = 0;while (n <= 100){nSum = nSum + n;n++;} printf("%d", nSum);system("pause");return 0; }

第二步,分析while循環(huán)的代碼定式。
注意,該循環(huán)的Debug版本和Release版本存在差異,接下來會對比分析。我們先給出代碼定式,如下所示。

//程序語言 while(xxx) {... }//代碼定式 WHILE_BEGIN:jxx WHILE_END...jmp WHILE_BEGIN WHILE_END:...

while循環(huán)的條件跳是往上跳的,它需要反復執(zhí)行同一代碼段。


第三步,通過OD打開運行的EXE程序“RE_XH.exe”。

  • 程序入口地址:0x00401260

第四步,往下查找代碼,發(fā)現(xiàn)3個PUSH后(參數(shù))就是主函數(shù),然后F2添加斷點并F7步入主函數(shù)。

  • 主函數(shù):CALL RE_XH.00401005


第五步,分析匯編代碼。
這里存在一個JG跳轉,它有點像if語句,下面還有一個JMP,有點像if-else指令,但是它的跳轉是地址減量跳或往上跳,所以它是循環(huán)。

這時會發(fā)現(xiàn)while循環(huán)比剛才的多了一個跳轉。我們會過計算機組成原理,當處理器執(zhí)行跳轉指令時,流水線會暫時掛起失效,本來流水線在取指令時已經(jīng)準備預讀后面的代碼了,結果在譯碼過程中是個跳轉,后面的代碼預讀就會出錯,然后做流水線清理工作。所以,while循環(huán)有兩跳對流水線的傷害比do-while大。


第六步,接著我們用高版本VS2019編譯一個Release版本,并用IDA進行分析,看看高版本有什么優(yōu)化。

查看Text View,我們定位到main函數(shù)之后,看看它做的優(yōu)化。它把循環(huán)的起點對齊到十六進制10的倍數(shù)地址,中間會用nop進行空指令填充。同時,它的匯編循環(huán)體變成了do-while循環(huán)。

注意,前面的VC++ Debug版本用IDA工具打開如下圖所示。上圖和下圖同樣都是while循環(huán),但低版本可以看到JG(往下跳)和JMP(往上跳)兩個跳轉,典型的while循環(huán);而高版本的卻修改成了do-while循環(huán)的形式。

問題1:由于do-while循環(huán)會執(zhí)行一次循環(huán)體,難道它不擔心編譯器出錯嗎?
其實它比較的數(shù)值是常量,常量可以在編譯期間預置其結果的,其實編譯器在第一次的判斷時先進行了一次常量傳播,令n等于1,即判斷的是 while(1<=100),比較1和100的關系條件必成立。

問題2:那么,如果將100替換成變量,編譯器還能識別嗎?或者會報錯?
此時的編譯器會將其進行轉換,變成如下圖所示的形式再執(zhí)行do-while循環(huán)。其中if(n<=argc)條件判斷嵌套一個循環(huán)。

對應的匯編代碼如下,其中“jl short loc_401016”往下跳,還原成一個單分支,循環(huán)里面還有一個跳轉“jle short loc_40100F”往上跳,滿足do-while循環(huán),最終還原成if加do-while,或者你知道有這個優(yōu)化,直接還原成帶變量的while循環(huán)也可以。

但需要注意,能不能把do-while直接還原成while循環(huán),還需要看看這兩個條件有沒有相關性。如果有相關性才能還原,比如外層判斷是文件的打開狀態(tài),while是迭代n值,這種情況不能還原。下圖可以看到if和循環(huán)都是EAX參數(shù)比較,所以具有相關性。



3.for結構分析

下面開始分析for循環(huán)結構。

for(表達式1;表達式2;表達式3;) {語句; }

第一步,我們編寫一個for循環(huán)代碼。

#include "stdafx.h" #include <stdlib.h>int main(int argc, char* argv[]) {int nSum = 0;for (int n = 1; n<=argc; n++){nSum = nSum + n;} printf("%d", nSum);system("pause");return 0; }

第二步,編譯生成新的Debug版可執(zhí)行程序。


第三步,通過IDA打開運行的EXE程序“RE_XH.exe”。
產出了三個跳轉代碼,如下圖所示。

其代碼定式如下所示,可以看到JMP、JG和JMP三個跳轉。注意,for循環(huán)中FOR_STEP地址是低于BODY執(zhí)行體的地址的。


第四步,分析匯編代碼。
首先MOV進行初始化賦值1,接著JMP跳轉到比較部分,比較不成立則JG直接跳出循環(huán),否則執(zhí)行循環(huán)體BODY內容,接著繼續(xù)JMP跳轉上去執(zhí)行n++操作。

注意,由于Release版本都被編譯器優(yōu)化成了do-while循環(huán),所以我們需要在Debug版下進行對比。


第五步,通過VS2019生成Release版本,然后用IDA打開代碼對比。

IDA打開如下圖所示,發(fā)現(xiàn)和do-while一樣,高版本做了一點小處理,每次循環(huán)總次數(shù)增加了4(add eax,4),從而提升效率。



三.總結

寫到這里,這篇文章就介紹完畢,希望對您有所幫助,最后進行簡單的總結下。

  • 條件語句逆向分析
  • 循環(huán)語句逆向分析

學安全一年,認識了很多安全大佬和朋友,希望大家一起進步。這篇文章中如果存在一些不足,還請海涵。作者作為網(wǎng)絡安全初學者的慢慢成長路吧!希望未來能更透徹撰寫相關文章。同時非常感謝參考文獻中的安全大佬們的文章分享,深知自己很菜,得努力前行。

2020年8月18新開的“娜璋AI安全之家”,主要圍繞Python大數(shù)據(jù)分析、網(wǎng)絡空間安全、人工智能、Web滲透及攻防技術進行講解,同時分享CCF、SCI、南核北核論文的算法實現(xiàn)。娜璋之家會更加系統(tǒng),并重構作者的所有文章,從零講解Python和安全,寫了近十年文章,真心想把自己所學所感所做分享出來,還請各位多多指教,真誠邀請您的關注!謝謝。

(By:Eastmount 2020-12-25 周五夜于武漢 https://blog.csdn.net/Eastmount)


參考資料:
真心推薦大家好好看看這些視頻和文章,感恩這些大佬!前非常推薦錢老師的視頻,感謝華科UP主。
[1] 科銳逆向的錢林松老師受華中科技大學邀請- “逆向分析計算引導”
[2] C語言逆向工程之游戲輔助開發(fā) - C語言Plus
[3] https://www.bilibili.com/video/BV1J5411x7qz?p=1

總結

以上是生活随笔為你收集整理的[系统安全] 六.逆向分析之条件语句和循环语句源码还原及流程控制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。