軟件保護(hù)殼技術(shù)專題_第1頁(yè)
軟件保護(hù)殼技術(shù)專題_第2頁(yè)
軟件保護(hù)殼技術(shù)專題_第3頁(yè)
軟件保護(hù)殼技術(shù)專題_第4頁(yè)
軟件保護(hù)殼技術(shù)專題_第5頁(yè)
已閱讀5頁(yè),還剩14頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、軟件保護(hù)殼技術(shù)專題 - 變形引擎的構(gòu)建 <目錄>1.需要變形的部分22.花指令的構(gòu)建32.1產(chǎn)生隨機(jī)寄存器42.2產(chǎn)生隨機(jī)的清052.3產(chǎn)生隨機(jī)的JMP82.4產(chǎn)生異常代碼82.5利用MODRM/SIB143.構(gòu)建解密頭144.另一種變形(1)155.另一種變形(2)166.總結(jié)191.需要變形的部分 殼的變形技術(shù)主要來(lái)自于病毒。病毒變形主要目的為了躲避殺毒軟件的查殺,殼的變形也無(wú)非是這個(gè)。當(dāng)然還有目的是為了延長(zhǎng)破解時(shí)間,消耗Cracker的精力?,F(xiàn)在看一個(gè)經(jīng)典的變形結(jié)構(gòu),也確認(rèn)哪部分是用來(lái)變形的殼加載段-解密頭殼主體被加密的部分密鑰儲(chǔ)存- 大多數(shù)情況下,殼加載器的結(jié)構(gòu)就是這三個(gè)部

2、分。解密頭對(duì)殼主體進(jìn)行解密后再跳入到殼主體進(jìn)行運(yùn)行。這里就可以很明顯的看出 殼主體是很容易進(jìn)行變形的,只要每次加密的密鑰不一樣最后的隊(duì)列肯定不一樣?,F(xiàn)在解密頭是固定的,所以這里是最需要進(jìn)行變形的。以上這個(gè)結(jié)構(gòu)絕對(duì)是經(jīng)典多態(tài)的結(jié)構(gòu),再?gòu)?fù)雜的變形也是從以上這個(gè)簡(jiǎn)單的結(jié)構(gòu)開始的。下面看一段簡(jiǎn)單的CODE。代碼:call deltadelta:pop esiadd esi, offset Packet - offset deltamov edi, esimov ecx, o

3、ffset Decoder - offset Packetmov eax, esiadd eax, offset Decoder - offset Packetmov bl, byte ptr eax:lodsbxor al, blstosbloop B; 這里解密后直接進(jìn)去殼主體Packet:;.殼主體Decoder:db 099h 以上就是簡(jiǎn)單的ASM代碼。這里的算法是XOR當(dāng)然比較

4、簡(jiǎn)單,當(dāng)然在解密之前要首先保證代碼段是可寫屬性。現(xiàn)在開始變形解密頭要如何變形呢?這里可以看出其實(shí)總共解密頭也沒幾個(gè)字節(jié),提出兩種通用方式。一個(gè)就是添加花指令構(gòu)建將花指令丟到解密頭每條指令中間。一個(gè)就是等價(jià)的代碼替換,寄存器的替換??傊饷茴^是我們自己編寫的。我們可以精心的去構(gòu)建一段代碼,并將此按照我們自己的規(guī)則進(jìn)行模板化。 每當(dāng)生成新的殼解密頭時(shí)進(jìn)行填充。當(dāng)然也可以用一些復(fù)雜的規(guī)則去擴(kuò)大這個(gè)結(jié)構(gòu)。自定義的模板規(guī)則,復(fù)雜的花指令生成等等。產(chǎn)生解密模板的時(shí)候可以適當(dāng)?shù)倪\(yùn)用一些編譯原理的技術(shù)。首先產(chǎn)生一個(gè)自己可以理解的中間指令,然后再翻譯成X86代碼。這樣的好處是可以無(wú)限的擴(kuò)充模板的形勢(shì),變形力度很

5、大。在病毒上可能實(shí)現(xiàn)要麻煩些,畢竟病毒要考慮到自身體積的大小,但是殼卻不用考慮那么多。另外一點(diǎn)要說(shuō)明的是做變形的時(shí)候不要拘泥于此格式,可以盡量發(fā)揮想象來(lái)做。例如把解密分段,或者將解密先寫入到棧中在執(zhí)行??傊_(dá)到惡心Cracker的目的就成。2.花指令的構(gòu)建 花指令的構(gòu)建方法有很多種,但是原理都是相同的在不影響運(yùn)行上下文的情況下,產(chǎn)生一些無(wú)效的指令。同樣下文以例子展出,如果自己做的,盡量發(fā)揮想象力。不用拘泥于這篇文章或者某篇文章。2.1產(chǎn)生隨機(jī)寄存器 每條指令對(duì)寄存器的操作的編碼都有一些規(guī)則,具體是什么規(guī)則可以讀下INTEL的編碼規(guī)則。這個(gè)專題里也有一篇是講反匯編引擎的,不過(guò)為了不產(chǎn)生歧義還是推

6、薦去看INTEL的手冊(cè)。這里也不講IA32的編碼規(guī)則了。直接來(lái)看些具體的例子$R表示寄存器,IMM(X)表示立即數(shù),例如MOV $R, IMM32,形如類似的移動(dòng)語(yǔ)句。OPCODE是B8 IMM32 這樣的。B8表示MOV EAX, 可以在OD里查看B9為MOV ECX,這里有個(gè)排序:從EAX開始為EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI這樣的順序。如果翻看MODRM/SIB規(guī)則可以看到這個(gè)排序規(guī)則,至于為什么要這樣排。

7、只能去問(wèn)INTEL公司了。INTEL手冊(cè)里也沒說(shuō)明。 總之MOV $R, IMM32可以變成為B8 B9 BA BB . 按照以上那個(gè)排序選取寄存器。其他指令也一樣例如POP $R是從58開始的.所以每次選取之需要很簡(jiǎn)單的一個(gè)隨機(jī)模8就可以了。 但是這里要排除一個(gè)意外就是esp。ESP控制著堆棧指針稍微有些不細(xì)心就會(huì)造成程序運(yùn)行錯(cuò)誤。為了保險(xiǎn)還是把它T出去好了。不過(guò)不是非要排除ESP。如果你的花指令產(chǎn)生器構(gòu)建的夠精密,模板夠好。也可以把ESP的變換也加進(jìn)來(lái)。為了穩(wěn)定,按照我謹(jǐn)慎的性格還是將它排除在外。SH

8、OW段代碼。C+的。代碼:const DWORD Registry_Eax = 0x00;const DWORD Registry_Ecx = 0x01;const DWORD Registry_Edx = 0x02;const DWORD Registry_Ebx = 0x03;const DWORD Registry_Esp = 0x04;const DWORD Regis

9、try_Ebp = 0x05;const DWORD Registry_Esi = 0x06;const DWORD Registry_Edi = 0x07;const DWORD Registry_MaxCount = 0x08;while (bR0 = Registry_Esp) bR0 = (BYTE)(lrand() % Registry_MaxCount);/

10、0;bR0是選取的寄存器,lrand是隨機(jī)函數(shù)2.2產(chǎn)生隨機(jī)的清0 在編寫代碼過(guò)程中請(qǐng)0操作是常用操作。sub $R,$R . xor $R,$R等都是常用的清0方式。我們把這些方式記錄下來(lái)并保存為我們的模板,如果你不喜歡單指令的。也可以做一些復(fù)雜些的模板 mov $R, IMM32; sub $R, IMM32-1; dec $R;都是可以的。以下展示段簡(jiǎn)單的C+代碼。代碼:const DWORD Clr0_Mov = 0x00;co

11、nst DWORD Clr0_Xor = 0x01;const DWORD Clr0_Sub = 0x02;DWORD MakeClearZero(LPBYTE pClearZero, DWORD dwBufSize, BYTE bRegistry)  / mov $R, 0  const BYTE MoveZeroBase = "xB8

12、x00x00x00x00"  / xor $R, $R  const BYTE XorZeroBase = "x33xC0"  / sub $R, $R  const BYTE SubZeroBase = "x2BxC0"  int nRand = 0;  i

13、f (dwBufSize >= 5)      lsrand(unsigned)time(NULL);    nRand = lrand() % 3;    if (nRand = Clr0_Mov)          memcpy(pClearZero

14、, MoveZeroBase, 0x05);      while (bRegistry = Registry_Esp)        bRegistry = (BYTE)(lrand() % Registry_MaxCount);      bRegistry += 0xB8; 

15、;     *(BYTE *)pClearZero = bRegistry;      return 0x05;        else if (nRand = Clr0_Xor)          memcpy(pClearZe

16、ro, XorZeroBase, 0x02);      while (bRegistry = Registry_Esp)        bRegistry = (BYTE)(lrand() % Registry_MaxCount);      bRegistry *= 0x09;

17、0;     bRegistry += 0xC0;      *(BYTE *)(pClearZero + 1) = bRegistry;      return 0x02;        else      

18、    memcpy(pClearZero, SubZeroBase, 0x02);      while (bRegistry = Registry_Esp)        bRegistry = (BYTE)(lrand() % Registry_MaxCount);     

19、; bRegistry *= 0x09;      bRegistry += 0xC0;      *(BYTE *)(pClearZero + 1) = bRegistry;      return 0x02;        e

20、lse if (dwBufSize >= 2)      lsrand(unsigned)time(NULL);    if (nRand = Clr0_Xor)          memcpy(pClearZero, XorZeroBase, 0x02);    

21、;  while (bRegistry = Registry_Esp)        bRegistry = (BYTE)(lrand() % Registry_MaxCount);      bRegistry *= 0x09;      bRegistry += 0

22、xC0;      *(BYTE *)(pClearZero + 1) = bRegistry;      return 0x02;        else          memcpy(pClearZero, SubZeroB

23、ase, 0x02);      while (bRegistry = Registry_Esp)        bRegistry = (BYTE)(lrand() % Registry_MaxCount);      bRegistry *= 0x09;   

24、60;  bRegistry += 0xC0;      *(BYTE *)(pClearZero + 1) = bRegistry;      return 0x02;        return 0;2.3產(chǎn)生隨機(jī)的JMP有了上面的基礎(chǔ),直接看實(shí)例代碼。代碼:DWORD Ge

25、nerateDummyJmp(PJUNKCODE_BASE pJunkCodeBase, LPBYTE pStart, DWORD dwJunkCodeSize)  const DWORD dwMinSize = 0x05;  if (dwJunkCodeSize < dwMinSize) return 0;  LPBYTE pEnd = pStart 

26、;+ dwJunkCodeSize;  / 只能產(chǎn)生向后跳的指令  BYTE JmpCodes = "xE9xFFxFFxFFxFF"  DWORD dwOffset = pEnd - pStart - 0x05;  *(DWORD *)&JmpCodes1 = dwOffset;  memcpy(pStart,

27、0;JmpCodes, 0x05);  / 生成花指令  DWORD dwRet = GenerateJunkCode(pJunkCodeBase, pStart + 0x05, dwOffset);  return (dwRet + 0x05);/ pJunkCodeBase 是 垃圾指令庫(kù),GenerateJunkCode是產(chǎn)生垃圾指令。進(jìn)行填充可以自行構(gòu)建2.4產(chǎn)生異常代碼/

28、60;這個(gè)其中有些函數(shù)是產(chǎn)生push pop的原理都一樣.有興趣的自己動(dòng)手DIY就OK了。原理很簡(jiǎn)單沒什么好寫的了DWORD NaTaSha:GenerateDummySehJmp(PJUNKCODE_BASE pJunkCodeBase, LPBYTE pHeader, DWORD dwHeaderSize)  / 基本型  / push $R0         1

29、byte  / push $R1         1byte  / call delta       5bytes  / delta:  / pop $R0         1byte &#

30、160;/ add $R0, dwOffset   6bytes  / push $R0         1byte  / xor $R1, $R1       2bytes  / push fs:$R1    

31、; 3bytes  / mov fs:$R1, esp   3bytes  / 觸發(fā)異常  / 垃圾代碼  / 執(zhí)行代碼  / pop fs:$R1       3bytes  / add esp, 04h    

32、60;  3bytes  / pop $R1         1byte  / pop $R0         1byte  const DWORD dwSehTotal = 0x80;  if (dwHeaderSize

33、0;< dwSehTotal) return 0;  LPBYTE pHandler = NULL, pCurr = pHeader;  / 模擬SEH跳轉(zhuǎn)的空間最小長(zhǎng)度為128個(gè)字節(jié)  const DWORD dwResumeStack = 0x06;/恢復(fù)異常處理堆棧長(zhǎng)度  DWORD dwRemain = dwHeaderSize,&#

34、160;dwSize = 0;  / 首先隨機(jī)選出兩個(gè)寄存器,為了避免意外,過(guò)濾掉esp寄存器  lsrand(unsigned)time(NULL);  / R0作為重定位與觸發(fā)異常,R1作為清0  BYTE bR0 = (BYTE)(lrand() % Registry_MaxCount), bR1 = (BYTE)(lrand() % Registry_MaxCount)

35、;  while (bR0 = Registry_Esp) bR0 = (BYTE)(lrand() % Registry_MaxCount);  while (bR1 = Registry_Esp) bR1 = (BYTE)(lrand() % Registry_MaxCount);    DWORD dwRet = 0;&#

36、160; / 保存寄存器  dwRet = MakePushValue(bR0);  *pCurr = (BYTE)dwRet;  dwSize+;  dwRemain-;  pCurr+;  dwRet = MakePushValue(bR1);  *pCurr = (BYTE)dwRet;  dwSize+;  d

37、wRemain-;  pCurr+;  / 重定位  LPBYTE pCall0 = pCurr;  dwRet = MakeRelocateCode(pCurr, dwRemain, bR0, 0);  dwSize += dwRet;  dwRemain -= dwRet;  pCurr += dwRet

38、;  DWORD dwCall0Size = dwRet;  / 壓入異常句柄  dwRet = MakePushValue(bR0);  *pCurr = (BYTE)dwRet;  dwSize+;  dwRemain-;  pCurr+;  / 清0  dwRet = MakeClearZero(pCu

39、rr, dwRemain, bR1);  dwSize += dwRet;  dwRemain -= dwRet;  pCurr += dwRet;  / 建立異常堆棧  const BYTE PushFsR = "x64xFFx30"/3字節(jié)  const BYTE MovEspR = 

40、"x64x89x20"/3字節(jié)  / push dword ptr fs:$R  memcpy(pCurr, PushFsR, 0x03);  *(pCurr + 0x02) = bR1 + 0x30;  dwSize += 0x03;  dwRemain -= 0x03;  pCurr 

41、+= 0x03;  / mov dword ptr fs:$R, esp  memcpy(pCurr, MovEspR, 0x03);  *(pCurr + 0x02) = bR1 + 0x20;  dwSize += 0x03;  dwRemain -= 0x03;  pCurr +=&

42、#160;0x03;  / 觸發(fā)異常  dwRet = MakeExpCode(pCurr, dwRemain, bR1);  dwSize += dwRet;  dwRemain -= dwRet;  pCurr += dwRet;  / 確定是否產(chǎn)生垃圾代碼  lsrand(unsigned)time(NULL); 

43、0;int nRand = lrand() % 2;  if (nRand = 0)/ 不產(chǎn)生垃圾代碼    goto GenerateExpHandler;  / 垃圾代碼  DWORD dwJunkCodeSize = dwRemain / 2;  nRand = lrand() %&

44、#160;dwJunkCodeSize;  dwJunkCodeSize = nRand + 1;/隨機(jī)長(zhǎng)度范圍在剩余長(zhǎng)度的一半之內(nèi)  dwRet = GenerateJunkCode(pJunkCodeBase, pCurr, dwJunkCodeSize);  dwSize += dwRet;  dwRemain -= dwRet;  pCurr += 

45、dwRet;  / 異常執(zhí)行函數(shù)GenerateExpHandler:  DWORD dwExpCodeSize = dwRemain - dwResumeStack;  dwRet = GenerateJunkCode(pJunkCodeBase, pCurr, dwExpCodeSize);  dwSize += dwRet;  dwRemain -= 

46、dwRet;  DWORD dwOffset = (DWORD)(pCurr - pCall0);  / 0x04為偏移長(zhǎng)度  *(DWORD *)(pCall0 + dwCall0Size - 0x04) = dwOffset;  pCurr += dwRet;  / 恢復(fù)異常堆棧  const BYTE&

47、#160;PopFsR = "x64x8Fx00"  const BYTE AddEsp4 = "x83xC4x04"  / pop dword ptr fs:$R  memcpy(pCurr, PopFsR, 0x03);  *(pCurr + 0x02) = bR1;  dwSize 

48、+= 0x03;  dwRemain -= 0x03;  pCurr += 0x03;  / add esp, 04h  memcpy(pCurr, AddEsp4, 0x03);  dwSize += 0x03;  dwRemain -= 0x03;  pCurr += 0x03; &#

49、160;return dwSize;2.5利用MODRM/SIB如果你不知道什么是MODRM/SIB去看看那篇反匯編引擎的構(gòu)建吧或者直接去都INTEL手冊(cè)。TMD這個(gè)殼里運(yùn)用了很多M/S這個(gè)結(jié)構(gòu)構(gòu)造的花指令。這種構(gòu)造很惡心尤其是聯(lián)合上JMP指令。每次你要想在OD里瀏覽代碼整體樣子。都必須要去修復(fù)這段代碼。相比脫過(guò)殼的朋友都遇上過(guò)這種。現(xiàn)在看一個(gè)基本型.其余復(fù)雜的形式靠自己想象了。再次鄭重想做好殼。要時(shí)刻保持豐富的想象力還有一顆“邪惡”的心。所謂是人至*則無(wú)敵。殼至*則無(wú)Cracker.-00401010:JMP 004013E 這里就跳入到了 dword

50、 ptr 4 * ebx + 0xFFFFEEEE這部分其余指令004013Dmov eax, dword ptr 4 * ebx + 0xFFFFEEEE 這里發(fā)揮一下想象力吧。dword ptr 4 * ebx + 0xFFFFEEEE 這部分是可是有足足6個(gè)字節(jié)的空間可以發(fā)揮想象力,但是通常只能利用到SIB位。因?yàn)镸ODRM位產(chǎn)生不了。當(dāng)Mod = 00 01 10 RM = 100 時(shí),那么它的下一個(gè)字節(jié)就是SIB了。通常JMP指令是個(gè)不錯(cuò)的選擇。因?yàn)樽铋L(zhǎng)的JMP也就5個(gè)字節(jié)剛好滿足。既有了花指令的作用,又可以對(duì)抗反匯編。一個(gè)不錯(cuò)的想法

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論