CE學(xué)習(xí)筆記

1.CE修改游戲特例說明

模擬器游戲不能直接修改游戲的程序代碼(即不能直接使用代碼注入的手段修改code段代碼),因?yàn)橛螒虿⒎鞘褂闷脚_(tái)語言所寫,只有模擬器是使用平臺(tái)語言寫的,即殼是匯編寫的,殼用來翻譯跨平臺(tái)程序,因此不能直接修改跨平臺(tái)程序。

2.精確搜索

精確搜索時(shí)需要根據(jù)具體的數(shù)值范圍(數(shù)據(jù)類型)搜索數(shù)據(jù):
例如:

  • 搜索時(shí)間,可能使用的浮點(diǎn)數(shù)存儲(chǔ)時(shí)間
  • 搜索字符串時(shí),可能使用字符數(shù)組存儲(chǔ)字符串

3.模糊搜索

當(dāng)模糊搜索的值再次搜索過濾多次還是很多時(shí),可以先精確搜索到能搜索到的地址,然后根據(jù)精確地址找模糊地址(因?yàn)槎际亲兞繑?shù)據(jù),都會(huì)存儲(chǔ)在data中,所以他們的地址應(yīng)該很近)
大部分游戲顯示的數(shù)值都經(jīng)過了加密(*2+1),因此需要模糊搜索來查找,以植物大戰(zhàn)僵尸的金幣為例:搜索值應(yīng)為游戲中金幣數(shù)/10(植物大戰(zhàn)僵尸的金幣最小單位為10),才可以搜到結(jié)果。

4.指針與多級(jí)指針

基址:

  • 基址, 即是程序代碼被編譯成二進(jìn)制碼時(shí)就已經(jīng)規(guī)定好的一個(gè)絕對(duì)地址值.一般反匯編后為: mov 寄存器, [xxxxxx] // 基址[xxxxxx]=模塊地址+偏移
  • 基址是一串16進(jìn)制數(shù)字代表的地址值, 除非程序被破壞,或者被重新編譯生成,否則是不會(huì)改變的。詳細(xì)可參考PE文件結(jié)構(gòu)。
  • 基址地址一般在程序模塊中(>00401000)(<7FXXXXXX系統(tǒng)領(lǐng)空)(綠色基地址)

指針:

  • 查找動(dòng)態(tài)地址指針時(shí)使用 是什么改寫 搜索
  • 查找指針地址時(shí)使用 是什么訪問 搜索

CE中基地址找到動(dòng)態(tài)地址:

  • [基地址(綠色模塊地址)]+偏移 取基地址值加上偏移值后的值作為地址(一級(jí)指針)
  • [[基地址(綠色模塊地址)]+偏移]+偏移 取一級(jí)指針的值+偏移值作為地址(二級(jí)指針)

32位游戲一般多級(jí)指針?biāo)阉鞯?級(jí)即可,64位一般最多則為8級(jí)或12級(jí),但是一般我們超過4級(jí)指針后可以通過人造指針來實(shí)現(xiàn)。

5.代碼注入—AOB注入

AOB注入是最常用的注入腳本,選中需要注入的代碼行,


AOB注入

彈出自動(dòng)匯編窗口中選擇AOB注入


AOB注入

生成代碼如圖:


AOB代碼

AOB腳本支持ENABLEDISABLE,因此可以加入到CT列表中,一鍵開啟或關(guān)閉腳本功能。

注入點(diǎn)
有時(shí)直接對(duì)當(dāng)前代碼行注入可能會(huì)造成程序報(bào)錯(cuò),選擇當(dāng)前代碼行的上一行注入可能會(huì)避免程序報(bào)錯(cuò)問題。

代碼注入點(diǎn)

6.匯編知識(shí)

寄存器

可以理解為一個(gè)臨時(shí)變量,每個(gè)寄存器有他們慣例的用途,不過這僅僅是慣例,你想用他們做其他事也可以(除了 esp 棧頂指針以外)。
通常我們使 eax, ebx,ecx, edx 做普通的操作,雖然這些寄存器也有一些特殊的用途,但是用途較少所以一般的操作用這些寄存器就可以。
esiedi:看他們的名字,叫做“源索引寄存器”和“目標(biāo)索引寄存器” (source index、destination index),因?yàn)樵诤芏嘧址僮髦噶钣玫模谄渌募拇嫫鞯臅r(shí)候不用這幾個(gè),當(dāng)然如果你能掌控得好的話 esi 和 edi 其實(shí)也可以隨便使用。
espesp 是不可以亂動(dòng)的,esp 指向堆棧頂部,pushpop 指令會(huì)影響 esp,由于寄存器的數(shù)量太少了,我們編寫程序時(shí)需要的變量有很多,所以使用內(nèi)存來輔助我們,函數(shù)的局部變量就會(huì)保存在棧中,調(diào)用函數(shù)的參數(shù)也會(huì)保存在棧中。
比如說,現(xiàn)在我們的寄存器都用完了,我需要騰出一個(gè)寄存器來做其他事情。那么就把寄存器的變量放到內(nèi)存(棧)中(push),然后就可以對(duì)這個(gè)寄存器為所欲為了,然后用完之后,再把棧中的值提取出來(pop),放回寄存器。

push eax
; 做一堆有關(guān)eax的事
; 比如:
; mov eax, [ebp+04]
; add eax, [edx]
; mov [ebp+04], eax
pop eax

常見指令

基礎(chǔ)指令集 —— 8086指令集
8086匯編指令總結(jié)

sse指令集
movss 表示 Move Scalar Single,移動(dòng)標(biāo)量單精度浮點(diǎn)值。
xorps 表示 XOR Packed Single,壓縮單精度浮點(diǎn)值邏輯位異或。
cvtps2pd 表示 Convert Packed Single to Packed Double,壓縮單精度浮點(diǎn)值轉(zhuǎn)換成壓縮雙精度浮點(diǎn)值。
addsd 表示 Add Scalar Double,標(biāo)量單精度浮點(diǎn)值加法。
mulsd 表示 Multiply Scalar Double,標(biāo)量單精度浮點(diǎn)值乘法。
這些可以直接進(jìn)行浮點(diǎn)運(yùn)算的指令、可以直接操作XMM寄存器的指令,都屬于 SSE 指令集。
每條匯編指令的名字起得都是有意義的,好好學(xué)習(xí)英語可以幫助我們更好地理解他們。
看到一條 SSE 指令,要把他拆成兩部分,“操作”和“數(shù)據(jù)類型”,
第一部分:操作。mov、xor、add、mul 這些指令,x86 最基礎(chǔ)的指令集中也有。
第二部分:數(shù)據(jù)類型。ss、sd、ps、pd 這一部分又要拆分成兩部分來看。第二位是 s 表示是 single 單精度浮點(diǎn)型,一個(gè)數(shù)據(jù)占 32 位,第二位是 d 表示 double 雙精度浮點(diǎn)型,一個(gè)數(shù)據(jù)占 64 位。第一位是 s 表示只操作 XMM 寄存器的第一個(gè)數(shù)據(jù)(ss 就是 32 位,sd 就是 64 位),第一位是 p 表示同時(shí)操作全部 128 位數(shù)據(jù)(ps 就是 4 個(gè) 32 位,pd 就是 2 個(gè) 64 位)。
xor 后面的兩個(gè)操作數(shù)相同的話就是用來清零的,比如 xor eax,eax 就是令 eax 為 0,這是最簡(jiǎn)單最快捷的寄存器清零方法。對(duì)于 XMM 寄存器同樣也是清零。
cvt 指令就是浮點(diǎn)數(shù)精度的轉(zhuǎn)換,主要看 s 和 d 的位置,s2d 就是 single to double 單精度浮點(diǎn)數(shù)到雙精度浮點(diǎn)數(shù),從只占 32 位變成占 64 位,反之 d2s就是雙精度到單精度的轉(zhuǎn)換。

常見的函數(shù)開頭

push ebp ; 保存上一個(gè) ebp
mov ebp, esp ; 把 esp 給 ebp
sub esp, 08 ; 分配8字節(jié)??臻g用于局部變量
; 函數(shù)主體內(nèi)容...
; 在這里可以使用 ebp 來定位與函數(shù)有關(guān)的變量
; [ebp-08] 代表第 2 個(gè)局部變量
; [ebp-04] 代表第 1 個(gè)局部變量
; [ebp] 剛才 push 進(jìn)來那個(gè) ebp
; [ebp+04] 函數(shù)返回之后的要執(zhí)行的指令所在位置
; [ebp+08] 代表函數(shù)的第 1 一個(gè)輸入?yún)?shù)
; [ebp+0C] 代表函數(shù)的第 2 個(gè)輸入?yún)?shù)
add esp, 08
pop ebp ; 復(fù)原 ebp
ret 08 ; 返回函數(shù)調(diào)用位置,并且把棧指針 +8,把調(diào)用的參數(shù)從棧中移除

范例

以植物大戰(zhàn)僵尸為例:
陽光地址是一個(gè)二級(jí)地址。查看反匯編代碼是這樣子的:

mov [eax*2 + edi + 00005578],esi

其中,edi是指針,eax*2 + 00005578是偏移值,esi是陽光數(shù)量,這句代碼的作用是把陽光的值放在陽光的內(nèi)存地址中。

7.共用代碼段的利用與處理

公共代碼段是代碼復(fù)用的體現(xiàn),好的代碼復(fù)用性很高,也就是說一個(gè)函數(shù)很可能供多個(gè)調(diào)用者調(diào)用。

針對(duì)公共代碼處理:
以火炬之光為例:
當(dāng)匯編nop了掉血代碼時(shí),發(fā)現(xiàn)不僅人物血不掉,而且怪物血也不掉了(因?yàn)榈粞瘮?shù)是人物與怪物扣血的共用函數(shù))。
使用代碼注入的方式時(shí),要利用cmpje jne jle等條件轉(zhuǎn)移指令判斷是否是己方還是敵方,達(dá)到己方不掉血。

以CE:STEP9為例:
STEP9中扣除血量的代碼就是公用代碼


CE:STEP9

先使用浮點(diǎn)搜索找到一個(gè)血量地址后,使用什么改寫搜索到代碼段地址,右鍵找出指令訪問的地址

公共代碼段

依次點(diǎn)擊攻擊,4個(gè)單位血量分別降低,可以看到4個(gè)單位的血量地址依次顯示出來。


4個(gè)單位的血量地址

全選地址,右鍵打開選中地址的分析數(shù)據(jù),彈窗默認(rèn)確認(rèn)即可,顯示如圖所示。

數(shù)據(jù)結(jié)構(gòu)

代碼注入(模版使用全部注入)如下:


代碼注入

匯編代碼

此時(shí)點(diǎn)擊攻擊,友軍不再會(huì)掉血。

利用公共代碼找相關(guān)地址:
當(dāng)我們找到物品欄的某個(gè)格子物品數(shù)量時(shí),可以通過掃描誰改寫了值找到改寫代碼處,再右鍵選擇“找出指令訪問的地址”打開掃描窗口,然后游戲中移動(dòng)物品到其他格子,就能找到這個(gè)代碼訪問的其他格子地址。原理即是利用公共代碼操作多個(gè)地址。

8.特征代碼的應(yīng)用 (針對(duì)程序段地址會(huì)變動(dòng))

1. 被迫使用特征碼:
以flash游戲國(guó)王的戰(zhàn)爭(zhēng)為例:
由于使用的flash啟動(dòng)的游戲,游戲的內(nèi)存地址每次都會(huì)不同(類似于模擬器游戲),因此只能根據(jù)特征碼(指令的字節(jié)數(shù)組)找到修改的地址,再做修改:

特征碼—代碼的字節(jié)數(shù)組

CEAA提供一個(gè)函數(shù)可以查詢特征碼的地址:

aobscan //CEAA函數(shù) 搜索特征碼,并將地址賦給變量

例:

aobscan(Money,特征碼)  把特征碼的地址給了money
money+修改地址的相對(duì)偏移量 即要修改代碼的地址

2. 主動(dòng)使用特征碼: 實(shí)現(xiàn)多版本兼容修改器
以植物大戰(zhàn)僵尸為例:有兩個(gè)版本(無盡版、年度版)進(jìn)程名相同,代碼實(shí)現(xiàn)相同(特征碼一樣),使用特征碼便可以實(shí)現(xiàn)通用的CT腳本。

9.人造指針 (針對(duì)指針級(jí)別過多、找不到基址的情況)

以植物大戰(zhàn)僵尸為例:
原理:陽光的地址每次重開游戲都會(huì)變化,有一個(gè)固定的程序段記錄陽光的地址

  • 方法一【固定地址】:
    (1) 右鍵陽光的地址是誰訪問了地址(讀取地址的值時(shí)觸發(fā),陽關(guān)地址是變動(dòng)的,只有訪問斷點(diǎn)可以找到是誰訪問了它),找到固定的程序段
    (2) 找到固定程序段-代碼注入
    (3) (a)找一處可讀可寫內(nèi)存模塊的空閑地址(固定地址)保存陽光地址
    (b)當(dāng)可讀可寫內(nèi)存地址沒有空閑時(shí),我們也可以使用只讀內(nèi)存的空閑地址,但是需要使用一條CE指令[fullaccess(只讀內(nèi)存地址,修改為可讀的字節(jié)長(zhǎng)度)修改內(nèi)存地址保護(hù)為可讀寫,這個(gè)指令不一定每次成功]
    (4) 建立指針指向空閑地址
  • 方法二【申請(qǐng)地址】:
    (1) 右鍵陽光的地址是誰訪問了地址(讀取地址的值時(shí)觸發(fā),陽關(guān)地址是變動(dòng)的,只有訪問斷點(diǎn)可以找到是誰訪問了它),找到固定的程序段
    (2) 找到固定程序段-代碼注入
    (3) 使用alloc(標(biāo)識(shí)名,地址長(zhǎng)度)動(dòng)態(tài)申請(qǐng)內(nèi)存,將陽光地址保存到申請(qǐng)的內(nèi)存中
    (4) 由于申請(qǐng)的內(nèi)存地址目前只能在當(dāng)前腳本中使用,我們需要將其保存到一個(gè)全局變量中,使得我們可以在其它腳本中也能訪問
    CEAA提供了一個(gè)函數(shù)命令[regiestersymbol(標(biāo)識(shí)名),表示將參數(shù)標(biāo)識(shí)加入到全局表]
    (5) 在[disable]中添加釋放申請(qǐng)內(nèi)存的指令dealloc(標(biāo)識(shí)名,地值長(zhǎng)度)
    (6) 前面將申請(qǐng)的內(nèi)存標(biāo)識(shí)加入了全局表,那么在關(guān)閉腳本時(shí)須將標(biāo)識(shí)從全局表中剔除
    [unregiestersymbol(標(biāo)識(shí)名),將參數(shù)標(biāo)識(shí)從全局表中剔除]
    (7) CE手動(dòng)添加地址,地址為標(biāo)識(shí)名

10.線程注入的應(yīng)用

以植物大戰(zhàn)僵尸修改陽光為例:

腳本代碼:

      [ENABLE]
      alloc(newmem,256)
      lable(exit)
      Createthread(newmem)
      newmem:
      mov eax,[755e0c]  //陽光基址
      mov eax,[eax+868]
      add [eax+5578],1F4
      cmp [eax+5578],2709 //陽光上限是9990
      jle exit
      mov [eax+5578],2706
      exit:
      ret
      [DISABLE]

線程注入效果:當(dāng)啟動(dòng)一次腳本陽光數(shù)量就+500,相當(dāng)于游戲修改器中點(diǎn)一次加一次屬性的操作。

11.Windows函數(shù)應(yīng)用

以火炬之光為例:
模擬自動(dòng)回藍(lán):判斷藍(lán)的值小于15時(shí),自動(dòng)摁2鍵吃藥

    [ENABLE]
    alloc(newmem.1024)
    lable(returnhere)
    lable(originalcode)
    label(exit)
    newmem:
    fld dword ptr [ecx+000003B8]
    cmp [ecx+000003B8],40A00000
    ja originalcode
    push 0
    push 0
    push 0
    push 32     //2鍵的鍵碼
    call keybd_event
    push 0
    push 0
    push 0
    push 32     //2鍵的鍵碼
    call keybd_event
    originalcode:
    exit:
    jmp returnhere
    Torchlight.exe+85FE0:
    jmp newmem
    nop
    ......

12.CE的斷點(diǎn)選擇與跟蹤

以皇家守衛(wèi)軍怪物秒殺為例:
在找到怪物血量減少的地方后應(yīng)該會(huì)有判斷怪物是否該死亡的跳轉(zhuǎn),修改跳轉(zhuǎn)完成秒殺功能

以植物大戰(zhàn)僵尸自動(dòng)收集陽光為例:
收集陽光的時(shí)候陽光會(huì)增加,下內(nèi)存寫入斷點(diǎn),找到陽光增加的語句,返回到上一層,在陽光增加call的上面會(huì)有點(diǎn)擊陽光的call,修改跳轉(zhuǎn)完成自動(dòng)收集陽光的功能

【三種斷點(diǎn)的原理】
(1)int 3斷點(diǎn),即cc斷點(diǎn),這是一種基于軟中斷機(jī)制斷點(diǎn),3為中斷號(hào)。OD中,當(dāng)你在代碼區(qū)某行按F2即可實(shí)現(xiàn),其機(jī)理是把所在代碼的第一個(gè)字節(jié)保存到一張表上,然后將其修改為CC,當(dāng)程序運(yùn)行到此代碼時(shí),就會(huì)產(chǎn)生中斷,從而轉(zhuǎn)至中斷服務(wù)程序。當(dāng)你去除斷點(diǎn)時(shí),OD會(huì)從表里讀取出當(dāng)前斷點(diǎn)原來的字節(jié)內(nèi)容。
(2)內(nèi)存斷點(diǎn),假如你用int 3斷點(diǎn)對(duì)數(shù)據(jù)區(qū)下斷,OD會(huì)提示你斷點(diǎn)可能不會(huì)實(shí)現(xiàn),其實(shí)也是必然,程序不可能執(zhí)行數(shù)據(jù)區(qū),然而我們卻可以當(dāng)數(shù)據(jù)被讀取或?qū)懭霑r(shí)進(jìn)行下斷,這種原理主要基于內(nèi)存屬性,當(dāng)下讀寫斷點(diǎn)是,OD會(huì)修改斷點(diǎn)處讀寫屬性,如果程序?qū)Υ藬?shù)據(jù)讀寫的話,會(huì)產(chǎn)生讀寫異常,OD捕捉此異常并分析,其可以知道運(yùn)行到何處,對(duì)代碼段也可以下此斷點(diǎn),機(jī)理相似。
(3)硬件斷點(diǎn),這是由硬件實(shí)現(xiàn)(這里是CPU實(shí)現(xiàn)),其由CPU調(diào)試器實(shí)現(xiàn),斷點(diǎn)長(zhǎng)度有限,其只用兩位記錄斷點(diǎn)長(zhǎng)度,所以只支持4個(gè)硬件斷點(diǎn),調(diào)試寄存器中有3位表示斷點(diǎn)狀態(tài)及屬性,000 保留 001 執(zhí)行斷點(diǎn) 010 訪問斷點(diǎn) 011 寫入斷點(diǎn) 100 保留 101 臨時(shí)斷點(diǎn) 110 保留 111 保留

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容