32位匯編第三講,RadAsm,IDE的配置和使用,以及匯編代碼注入方式


 

 

    32位匯編第三講,RadAsm,IDE的配置和使用,以及匯編代碼注入方式

一丶RadAsm的配置和使用

簡介:

2020.4.29 添加更正內容

更正內容:

  如果只想看RadAsm配置以及使用,可以查看新版配置 https://www.cnblogs.com/iBinary/p/12802276.html 當前博客講解的是舊版的設置.下面內容介紹了一個注入.注入可以學習一下.使用RadAsm編寫

 

正文:

 

用了怎么長時間的命令行方式,我們發現了幾個問題

1.沒有代碼提醒功能

2.編寫代碼很慢,記不住各種聲明

那么現在有大神,已經幫我們做了一個IDE環境,就是RadAsm,首先簡單介紹一下界面

(對於這個IDE(最新版是3.0)我已經打包好了,有中文版本,和英文版本)

我們需要配置一下環境

1.配置編譯環境,配置lib文件庫,配置Debug調試器

打開后會彈出

 

1.1 配置調試器路徑

首先這里我們注意下面的幾個選項

1.編譯選項 Assemble : 這個是默認的即可,如果你是編譯32位程序,那么我們就用 /c /coff 即可,后面幾個默認

2.連接選項 link:  一般是默認的,他是默認生成windows的程序,如果我們有控制台的程序,那么我們可以手工去編譯,

也可以通過它的項目,新建項目的時候選擇指定的

3.擴展的調試器 External debugger: 這個則配置我們od所在的路徑即可,3.0版本已經可以支持選擇調試器了,以前的版本則是你指定文件夾,默認的調試器是Ollydbg.exe,所以我們名字還要改為這個才可以

4.library: 庫的路徑,有時候你編寫匯編程序,會使用lib庫,也會使用inc文件,那么可以把我們昨天的MASM32的庫路徑放到這里,也可以用高版本的,比如vc++6.0的,或者vs系列的都是可以的

注意:

  上面配置的編譯選項,以及連接選項,我們都是安裝的MASM32的,也就是昨天提供的工具,我們把它的路徑設置為環境變量,這樣就可以用編譯的指令了,例如 /c /coff ....,如果你沒有安裝,或者沒有配置環境變量,那么計算機就會找不到編譯器,進而你的/c /coff就是錯誤的,所以我們還需要設置環境變量

1.2 RadAsm 3.0版本設置環境變量

  上面我們已經設置了調試器.下面我們設置環境變量

點擊 Option -> Environment

彈出界面

可以看到有三個路徑:

path include lib

分別加上我們的MASM 目錄即可.

例如Path

你的Masm路徑\bin

include 路徑

 

 lib 路徑同上

 建議使用Radasm 3.0 雖然是英文版.都是單詞都很簡單. 以前的我用了下有Bug. 例如程序運行之后不關閉.

2.RadAsm的字體設置,以及中文亂碼問題解決

關於RadAsm的字體,以及中文亂碼,網上有很多解決方法,這里我只對當前最新版本的RadAsm3.0做一個講解

選擇代碼編輯

從上往下看

1.第一個紅框,選擇的是Masm的背景顏色,以及主題,這個可以自由設置不多做講解

2.第二個紅框,Tab Size 4,這里是編寫匯編代碼的時候Tab制表符,的距離,我們可以設置為2個

3.第三個紅框,分別有個Code(代碼按鈕),和Line Number(行號的按鈕)

這里則是設置代碼字體的大小,還有行號顯示的大小

首先中文亂碼問題,打開code(代碼編輯)

在這里設置代碼字體的時候,一定注意要把下面的語言換成  ""中文 GB2312 " 而不是默西歐語言

選擇了即可解決中文亂碼的問題

 三丶建立RadAsm工程,以及編譯編譯連接,和調試

1.打開 Project(項目) - > new Project(新建項目)

2.選擇項目編譯的語言,(這里我使用masm),選擇項目生成的路徑

默認即可

編寫我們的第一段代碼,並且調試輸出

1,編譯連接一起執行

,

快捷鍵是Ctrl + F5  編譯運行

1.編譯快捷鍵 是 F5 會生成obj中間文件

3.鏈接快捷鍵是 Ctrl + Alt + F5   將obj文件生成exe

4. 編譯並連接 shift + alt + f5 直接將編譯連接在一起了.

4.調試快捷鍵是 Ctrl + D 它會默認打開我們的OD調試器,並且附加我們的程序,我們試一下

 

打開了我們的OD調試器,並且開始調試了

 

打開了我們的OD調試器,並且開始調試了

其余功能,自己嘗試,如果不會配置,也可以在下方評論,那么我看到則會幫你解決,然后如果有好心人看到也會幫你一把

 二丶匯編程序的注入代碼,注入32位計算機,並且彈出個信息框

一丶遠程線程注入的講解

在講解匯編程序注入代碼的時候,我們需要先明白,遠程線程注入的原理,我會寫一個遠程線程開發的例子,這樣有助於我們理解匯編注入

我們總共需要幾步

     /*1.查找窗口,獲取窗口句柄*/

    /*2.根據窗口句柄,獲得進程的PID*/

    /*3.根據進程的PID,獲得進程的句柄*/

    /*4.根據進程的句柄,給進程申請額外內存空間*/

    /*5.調用WriteProcessMemory,給進程寫入DLL的路徑*/

    /*6.創建遠程線程,執行我們的代碼*/

    /*7.調用退出代碼,釋放遠程線程的dll*/

每一步單獨講解

我們新建一個MFC 對話框程序,添加一個按鈕,這個按鈕專門響應注入的實現

第一步: 查找窗口,獲得窗口句柄(采用WindowsAPI FindWindow,傳入窗口名稱,然后找到則返回對應的窗口句柄)

    HWND hWnd = FindWindow("","計算器");
    if(NULL == hWnd)
    {
        return;              //失敗則返回
    }

第二步: 根據窗口句柄,查找進程PID (調用 GetWindowThreadProcessId API,傳入窗口句柄,然后通過第二個參數把進程的PID給我們的參數)

  

  /*2.根據窗口句柄,獲得進程的PID*/
    DWORD DwPid = 0;
    GetWindowThreadProcessId(hWnd,&DwPid); //這個函數會返回線程的ID,但是我們不關心,所以沒有加返回值

第三步: 根據進程PID,返回進程的句柄(OpenProcess,參數一,權限 參數二,句柄是否繼承,參數三,進程的pid)

 /*3.根據進程的PID,獲得進程的句柄*/
    HANDLE hProHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,DwPid);  //參數一,選擇所有權限,參數二,不繼承給false,參數三,給我們上面獲得的pid的值
    if(NULL == hProHandle)
    {
        return;
    }

第四步: 給遠程進程申請空間,並且返回空間的首地址(調用的API 是VirtualAllocEx)

/*4.根據進程的句柄,給進程申請額外內存空間*/
    LPVOID lpAddr = VirtualAllocEx(hProHandle,NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
    if(NULL == lpAddr)
    {
        return ;
    }
VirtualAllocEx說明:
第一個參數: 進程的句柄
第二個參數: 指定位置分配內存,給NULL為默認幫我們找塊地方申請內存(不過這個地址會返回,所以不關心)
第三個參數: 內存分配多大,我們給了4096個字節大小,也就是一個分頁(1000H)
第四個參數: 是否立即申請,還是保留這塊內存,只能給我們用,但是還沒申請,我們選擇立即申請
第五個參數: 權限,你申請的這塊內存是什么內存,只能讀,還是只能寫,還是只能執行,我們選擇全部,可讀可寫可執行

第五步:調用WriteProcessMemory將我們的Dll路徑,寫入到遠程進程中

/*5.調用WriteProcessMemory,給進程寫入DLL的路徑*/
    char szBuf[MAX_PATH] = {NULL};
    GetCurrentDirectory(sizeof(szBuf),szBuf); //這三行代碼主要是拼接我們的DLL,DLL是我們自己寫的
    strcat(szBuf,"StaticDll.dll");       //DLL這里就不寫了,用我的吧,我會發上去的
BOOL bRet
= WriteProcessMemory(hProHandle,lpAddr,szBuf,strlen(szBuf)+1,NULL); if(!bRet) { return; }
WriteProcessMemory講解:
第一個參數: 進程的句柄,可以用我們上面的OpenProcess返回的
第二個參數: 你要寫入的地址,地址使我們VirtualAllocEx申請之后返回的(就是你要往哪個地址寫內容)
第三個參數: 你寫入的內容是什么,寫入的內容使我們的Dll路徑,上面已經拼接好了
第四個參數: 你寫入的內容的大小是多大,這里我們用strlen求出來了
第五個參數: 實際寫入的個數,我們不關心,如果你想知道,則定義一個變量,然后 取地址傳入即可,因為是個指針

第六步: 遠程進程開辟線程,調用LoadLibrary,加載我們的dll,而你們知道,當dll被加載的時候,會有信息

所以我們在我們的dll里面寫入我們自己的代碼,比如這個dll被加載的時候,我們執行我們的代碼,

這里我的代碼就是找到計算器,然后給它加個菜單,並且響應消息

    HANDLE hThreadHandle = CreateRemoteThread(hProHandle,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)LoadLibrary,
        lpAddr,
        0,
        NULL);
核心代碼就在這里,我們必須要知道,我們現在加載我們的DLL,而我們的DLL被加載的時候,就要執行自己的代碼
所以這個時候就可以執行代碼了
CreateRemoteThread講解:
第一個參數: 進程的句柄(你要往哪個進程開辟線程)
第二個參數: 安全屬性,句柄可否繼承,不需要給NULL
第三個參數: 棧的大小,給0則默認
第四個參數: 函數執行,我們要開辟線程,開辟的線程叫做loadLibrary
第五個參數: 開辟線程傳入的參數,我們知道,線程只有一個參數,而現在正好load也是一個參數,所以加載的參數就是我們的
寫入遠程進程內存的dll路徑,而dll路徑一旦啟動,則會執行自己的代碼(核心,一定掌握)
第六個參數: 創建的標志,默認給0
第七個參數: 線程的ID,不需要知道,給NULL

我們嘗試一下是否可以成功注入計算器,並且加入菜單

已經成功注入了.對於完整的代碼,我會放到課堂資料中,但是這幾步,一定要親自手動弄明白

(備注: 我是使用VC++6.0編寫代碼,是MFC程序,當然你也可以用高版本,參考我這個,是一樣的

對於DLL,我也會發,你們可以自己去寫自己的DLL,比如一個空DLL會有DLL main,也就是dll的入口點

當第一次加載的時候會來信息什么的,所以可以在里面寫代碼.dll靠自己,這里只提供思路)

二丶匯編代碼的注入

注意,別看博客每天內容很少,其實你想真正掌握,沒有2-3個小時就不算掌握,當你真正明白這個知識點了,那才叫掌握,而不是看一遍就走的,自以為已經會了,千萬不要眼高手低

比如上面的遠程線程注入,原理是什么,雖然我代碼給你了,當你知道原理了,那么代碼自己就會寫了

原理: 原理就是找到進程,利用VirtualAllocEX給他開辟個空間,利用他的返回值,會返回這個空間的地址

然后再利用WriteProcessMemory給這塊空間寫入DLL的路徑,最后利用遠程線程(CreateRemoteThread)

把loadlibrary當做線程回調執行,傳入的參數就是遠程進程空間我們寫入的DLL路徑,

這樣相當於當另一個進程 調用了LoadLibray,並且加載我們的DLL,而利用DLL被加載會執行的機制,

然后在我們的DLL中寫入被加載時候的代碼即可.

(對於為什么我們確定loadlibary在遠程進程中,其實這個是系統的特性,重要你軟件一啟動,就必然要有dll的支持

而我們調用的loadlibary就在這些dll中)

廢話補多少,會的人請看今天重要的知識,匯編代碼注入

首先,前邊介紹了RadAsm的IDE環境,那么我們利用他建立一個Dlg匯編程序

1.首先,新建工程,創建一個窗口程序

(因為對於RadAsm3.0不太熟悉,所以這里不用3.0了,還是用2.2.2.0)

選擇win32 app

選擇 dialog app

生成的時候注意ID和窗口名

,對於ID,和IDname,我們需要自己去定義宏

然后在窗口過程函數相應我們的消息

注意,對於資源,我們必須單獨編譯,快捷鍵是 shift + F5

Ctrl + F5 編譯運行

現在已經可以正常執行了

我們OD看一下,

Ctrl + D

下斷點之后,消息來了,我們知道了WM_COMMAND消息是0x111,所以就直接調用MessageBox函數了

 開始遠程線程匯編代碼的編寫(因時間問題,今天只會講解一個思路,具體的實現代碼回去自己去寫一下)

明天公布答案,以及坑

看匯編代碼,我們會執行上面的那幾個步驟

先把變量定義出來

  LOCAL @hWnd:HWND              ;查找窗口返回窗口句柄
  LOCAL @hProcessHandle:HANDLE: ;進程句柄
  LOCAL @dwPid:DWORD            ;進程的PID
  LOCAL @lpBuf:PVOID            ;遠程進程開辟空間的首地址
  LOCAL @hThread:HANDLE         ;線程的句柄
  LOCAL @dwExitCode:DWORD       ;退出代碼,獲取的是遠程load的返回值
                    ;這些變量都是定義在窗口過程函數中

第一步,判斷按鈕ID,並且查找窗口句柄

;1.解析低位,獲得按鈕消息,並且查找窗口句柄
    invoke FindWindow,NULL, offset g_szWindowName
    mov @hWnd,eax     ;把返回值給@hWnd
     .if eax == NULL
      ret
    .endif

第二步:獲得進程的PID

invoke GetWindowThreadProcessId, @hWnd, addr @dwPID

第三步: 獲得進程句柄

invoke OpenProcess,PROCESS_ALL_ACCESS, FALSE, @dwPID

  mov @hProcess, eax
  .if eax == NULL
   ret
  .endif

第四步:申請內存空間

invoke VirtualAllocEx,@hProcess, NULL, 1000h, MEM_COMMIT, PAGE_EXECUTE_READWRITE
        mov @lpBuff, eax
        .if eax == NULL
          invoke ShowLastError
          ret
        .endif

第五步: 直接寫入代碼,寫入(按照以前,是往內存寫入DLL路徑,這里我們把代碼寫進去)

invoke WriteProcessMemory,@hProcess, 
                                   @lpBuff, 
                                   INJECT_CODE,         ;代碼的標號
                                   start - INJECT_CODE,     ;起始位置-標號等於實際大小
                                   NULL

標號是寫在代碼區的上面的

一會OD調試一下看看

至於為什么寫入的代碼要ret 4,也就是start上面的那句話,是因為

下面我們調用CreateRemoteThread的時候,其中一個參數是@lpbuf,我們是當做函數調用的,所以壓入一個返回地址

第六步: 創建遠程線程

invoke CreateRemoteThread,@hProcess, NULL, 0, @lpBuf, NULL, 0, NULL
        mov @hThread, eax
        .if eax == NULL
          ret
        .endif

        invoke WaitForSingleObject,@hThread, INFINITE  等待結束
        invoke GetExitCodeThread, @hThread, addr @dwExitCode 獲取loadlibrary的返回值
他的返回值其實是dll在內存中的實例句柄,所以我們需要釋放掉.(釋放自己可以搜一下,暫時先把主要的講了)

OD分析 明天講解,今天先熟悉一下代碼,內容比較多,消化一下

 課堂資料:

  鏈接:http://pan.baidu.com/s/1o7B9f2i 密碼:5kcu


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM