【原創】記憶體斷點快速定位分析CCProxy6.0字串加密演算法

看雪資料發表於2015-11-15

記憶體斷點快速定位分析CCProxy6.0字串加密演算法
  
 CCProxy相信大家都很熟悉了吧,他的註冊演算法肯定也被大家研究過了,今天我們這篇文章來分析一下他的字串加密演算法。
[Cracker]     : prince
[時間]        : 2005.01.23
[宣告]        : 只做技術交流,不做商業用途,如果你手頭寬裕並喜歡這個軟體的話請支援正版軟體。
[E-mail]      : Cracker_prince@163.com
[保護方式]    : 序列號
[外殼保護]    : 無
[編譯器/語言] : Microsoft Visual C++ 6.0


  公司在伺服器上裝了CCProxy6.0,對公司內部每臺PC上網都做了限制(網路卡MAC地址繫結),結果大家不

能上QQ,MSN,BT,就連帶WEB郵箱的網站也不能訪問,發郵件也不能超過10K!真是~!#¥%・!極度鬱悶罵公

司極度變態。就這麼算了嗎?呵呵,當然不會,不然就不會出這篇菜文了。不久前,大概一個月前左右吧,牛

人們發現了CCProxy6.0緩衝區溢位漏洞,寫出了溢位工具,爽啊!用工具輕鬆拿到了伺服器的shell,哼哼,看

我怎麼搞你!找到CCProxy的安裝目錄,檢視CCProxy.ini檔案內容,秘密可就在其中啊!二話不說在我的機器

上也裝上CCProxy6.0,拿回伺服器的CCProxy.ini檔案(具體怎樣拿回不是我們的討論範圍,所以略去),覆蓋本

機的原配置檔案,然後在本機修改配置再將配置檔案COPY回伺服器覆蓋,這樣我們的配置就生效了。哈哈,真

是不錯,等等,這是什麼?要密碼才能配置?沒關係,在配置檔案中找到Password關鍵字,“=”後面就是密碼

了,不過被作者加了密。這個更簡單,將密碼剪下到其他地方儲存,然後再啟動軟體就可以用空密碼配置了。

修改完後再把密碼貼上回來,OK,天衣無縫了。搞定!上網是沒有什麼限制了,可是好不容易拿到的shell不留

後門啟不是太虧了?對網路安全稍微瞭解的人都知道,通常人們都會習慣性的使用同一個密碼,那麼剛才我們

看到的密碼如果是伺服器的Administrator的密碼的話,後門也省了,哈哈。說幹就幹,抄起OD...

  軟體在啟動的時候肯定是要讀取配置檔案的內容來對自身進行配置,在使用者修改完密碼後也要將使用者

輸入的保護密碼進行加密後寫回配置檔案,所以我們可以下斷點CreateFileA來對軟體啟動時讀取配置檔案時攔

截,也可以選擇在使用者輸入完密碼儲存時,下斷點GetWindowTextA攔截密碼比較,進一步跟蹤到密碼加密的地

方進行分析。我們要得到密碼,首選斷點就是GetWindowTextA。下斷點GetWindowTextA,F9執行,被斷下很多

次,但在要求輸入密碼對話方塊出現之前都不是目標,一直F9直到點選設定彈出輸入密碼對話方塊,輸入假碼

87654321,確定,被斷在這裡:

----------------------------------------------------------------------------------------
00458B9E  |.  50   PUSH EAX
00458B9F  |.  E8 4>CALL CCProxy.004551F1
00458BA4  |.  50   PUSH EAX                                 ; |Buffer
00458BA5  |.  56   PUSH ESI                                 ; |hWnd
00458BA6  |.  FF15>CALL DWORD PTR DS:[<&USER32.GetWindowTex>; \GetWindowTextA  斷在這裡
00458BAC  |.  8B4D>MOV ECX,DWORD PTR SS:[EBP+10]
00458BAF  |.  6A F>PUSH -1
00458BB1  |.  E8 1>CALL CCProxy.004551C9
00458BB6  |.  EB 0>JMP SHORT CCProxy.00458BC3
00458BB8  |>  8B45>MOV EAX,DWORD PTR SS:[EBP+10]
00458BBB  |.  FF30 PUSH DWORD PTR DS:[EAX]                  ; /Arg2
00458BBD  |.  56   PUSH ESI                                 ; |Arg1
00458BBE  |.  E8 8>CALL CCProxy.00457C49                    ; \CCProxy.00457C49
00458BC3  |>  5F   POP EDI                                  ;  0015ABB0
00458BC4  |.  5E   POP ESI
00458BC5  |.  5D   POP EBP
00458BC6  \.  C2 0>RETN 0C

----------------------------------------------------------------------------------------
  接下來F8單步跟蹤,很容易來到這裡:
----------------------------------------------------------------------------------------
00427A6A   .  56   PUSH ESI
00427A6B   .  8BF1 MOV ESI,ECX
00427A6D   .  6A 0>PUSH 1
00427A6F   .  E8 D>CALL CCProxy.00453951
00427A74   .  8B46>MOV EAX,DWORD PTR DS:[ESI+5C]
00427A77   .  68 2>PUSH CCProxy.004FC924           ; /Arg2 = 004FC924 ASCII "abc"      真碼
00427A7C   .  50   PUSH EAX                        ; |Arg1 = 014F7578 ASCII "87654321" 假碼
00427A7D   .  E8 3>CALL CCProxy.0043FBB4           ; \CCProxy.0043FBB4
00427A82   .  83C4>ADD ESP,8
00427A85   .  85C0 TEST EAX,EAX
00427A87   .  74 5>JE SHORT CCProxy.00427ADA
00427A89   .  57   PUSH EDI
00427A8A   .  8BCE MOV ECX,ESI
00427A8C   .  C705>MOV DWORD PTR DS:[4FD128],0
00427A96   .  E8 C>CALL CCProxy.0045155B
00427A9B   .  A0 8>MOV AL,BYTE PTR DS:[477F80]
00427AA0   .  B9 0>MOV ECX,400

----------------------------------------------------------------------------------------
  用abc試試看,哈,成功了!再用Administrator和密碼abc登陸,嘿!真是老天對我不薄啊!又成功啦

!以後就可以用Administrator登陸啦!(說明:真正的密碼當然不是這個了,Boss是不會這麼傻D)。CCProxy還

是失敗在明碼比較。不管他,既然已經分析到這步了,我們來看看他是怎麼對字串加密的吧(暈,才進入正題

)。那麼怎樣快速定位字元解密的程式碼位置呢?我們這裡重點分析密文解密演算法。清除所有斷點,F2重新載入程

序,下斷CreateFileA, F9執行,斷在0041B1CA,此時我們使用記憶體斷點快速定位,ALT + M開啟記憶體映象,搜

索ASCII碼密文:"902901900",找到一處,就在這裡下記憶體訪問斷點,F9執行,斷在這裡:
-----------------------------------------------------------------------------------------
00409FD2  |.  57   PUSH EDI
00409FD3  |.  B9 0>MOV ECX,400                     ;  ECX=400h
00409FD8  |.  33C0 XOR EAX,EAX                     ;  EAX清零
00409FDA  |.  8D7C>LEA EDI,DWORD PTR SS:[ESP+D]
00409FDE  |.  8854>MOV BYTE PTR SS:[ESP+C],DL      ;  0寫入堆疊[ESP+C]
00409FE2  |.  F3:A>REP STOS DWORD PTR ES:[EDI]     ;  重複字首,重複次數CX=400h(1024d),執行完

ECX=0
00409FE4  |.  B9 0>MOV ECX,400                     ;  ECX=400h
00409FE9  |.  8DBC>LEA EDI,DWORD PTR SS:[ESP+1411] ;  [ESP+1411]=0012BBA1
00409FF0  |.  8894>MOV BYTE PTR SS:[ESP+1410],DL   ;  將DL=0寫入堆疊[ESP+1410]
00409FF7  |.  8D54>LEA EDX,DWORD PTR SS:[ESP+C]    ;  [ESP+C]=0,ESP+C=0x12A79C
00409FFB  |.  F3:A>REP STOS DWORD PTR ES:[EDI]     ;  重複字首,執行完ECX清零
00409FFD  |.  8BBC>MOV EDI,DWORD PTR SS:[ESP+341C] ;  [ESP+0x341C]為加密字串
0040A004  |.  83C9>OR ECX,FFFFFFFF                 ;  0 OR FFFFFFFF
0040A007  |.  F2:A>REPNE SCAS BYTE PTR ES:[EDI]    ;  斷在這裡,結果ECX=FFFFFFF5
0040A009  |.  F7D1 NOT ECX                         ;  ~FFFFFFF5==0xA
0040A00B  |.  2BF9 SUB EDI,ECX                     ;  將EDI指標指向密文
0040A00D  |.  33ED XOR EBP,EBP                     ;  EBP清零
0040A00F  |.  8BC1 MOV EAX,ECX                     ;  ECX=0xA
0040A011  |.  8BF7 MOV ESI,EDI                     ;  EDI==密文902901900
0040A013  |.  8BFA MOV EDI,EDX                     ;  EDX==0x12A79C
0040A015  |.  C1E9>SHR ECX,2                       ;  0xA>>2==2
0040A018  |.  F3:A>REP MOVS DWORD PTR ES:[EDI],DWO>;  EDX=90290190,同時ECX清零
0040A01A  |.  8BC8 MOV ECX,EAX                     ;  EAX==0xA
0040A01C  |.  33C0 XOR EAX,EAX                     ;  EAX清零
0040A01E  |.  83E1>AND ECX,3                       ;  0xA and 3 == 2
0040A021  |.  F3:A>REP MOVS BYTE PTR ES:[EDI],BYTE>;  執行完EDX=902901900,ECX清零
0040A023  |.  8D7C>LEA EDI,DWORD PTR SS:[ESP+C]    ;  密文地址存入EDI
0040A027  |.  83C9>OR ECX,FFFFFFFF                 ;  0 OR FFFFFFFF==FFFFFFFF
0040A02A  |.  F2:A>REPNE SCAS BYTE PTR ES:[EDI]    ;  執行完ECX=FFFFFFF5
0040A02C  |.  F7D1 NOT ECX                         ;  取反之後ECX=0xA
0040A02E  |.  49   DEC ECX                         ;  0xA-1=9,以上操作實際上是取密文個數
0040A02F  |.  B8 A>MOV EAX,AAAAAAAB
0040A034  |.  F7E1 MUL ECX                         ;  EAX*ECX(9),結果60000003,EAX=3,EDX=6
0040A036  |.  D1EA SHR EDX,1                       ;  EDX=6>>1==3
0040A038  |.  0F84>JE CCProxy.0040A0F0
0040A03E  |.  53   PUSH EBX
0040A03F  |.  8D5C>LEA EBX,DWORD PTR SS:[ESP+10]   ;  [ESP+10]為加密字串
0040A043  |>  8BFB /MOV EDI,EBX                    ;  EBX=密文902901900
0040A045  |.  83C9>|OR ECX,FFFFFFFF                ;  9 OR FFFFFFFF = FFFFFFFF
0040A048  |.  33C0 |XOR EAX,EAX                    ;  EAX清零
0040A04A  |.  8D94>|LEA EDX,DWORD PTR SS:[ESP+2418>;  ESP+2418==0x12CBA4
0040A051  |.  F2:A>|REPNE SCAS BYTE PTR ES:[EDI]   ;  執行完ECX=FFFFFFF5
0040A053  |.  F7D1 |NOT ECX                        ;  取反ECX=0xA
0040A055  |.  2BF9 |SUB EDI,ECX                    ;  將EDI指標指向密文902901900
0040A057  |.  8BC1 |MOV EAX,ECX                    ;  ECX=0xA
0040A059  |.  8BF7 |MOV ESI,EDI                    ;  EDI=密文902901900
0040A05B  |.  8BFA |MOV EDI,EDX                    ;  EDX=0x12CBA4
0040A05D  |.  C1E9>|SHR ECX,2                      ;  0xA >> 2==2
0040A060  |.  F3:A>|REP MOVS DWORD PTR ES:[EDI],DW>;  執行完ECX=0,EDX=90290190
0040A062  |.  8BC8 |MOV ECX,EAX                    ;  EAX=0xA
0040A064  |.  83E1>|AND ECX,3                      ;  ECX=(0xA and 3)=2
0040A067  |.  F3:A>|REP MOVS BYTE PTR ES:[EDI],BYT>;  執行完ECX=0,EDX=密文902901900
0040A069  |.  8D8C>|LEA ECX,DWORD PTR SS:[ESP+2418>;  密文地址存入ECX
0040A070  |.  C684>|MOV BYTE PTR SS:[ESP+241B],0   ;  將0寫入堆疊,代替原來的901中的9,目的是擷取

密文的前3個字元
0040A078  |.  51   |PUSH ECX                       ;  密文的前3個字元壓棧,"902"
0040A079  |.  E8 2>|CALL CCProxy.0043FBA9          ;  關鍵函式,單個字元解密,跟進
0040A07E  |.  B9 E>|MOV ECX,3E7                    ;  0x3E7送入ECX
0040A083  |.  8D94>|LEA EDX,DWORD PTR SS:[ESP+1018>;  堆疊地址[ESP+1018]=0x12B7A0
0040A08A  |.  2BC8 |SUB ECX,EAX                    ;  3E7-386=61
0040A08C  |.  51   |PUSH ECX                       ;  此處即為解密結果
0040A08D  |.  68 E>|PUSH CCProxy.004730E0          ;  ASCII "%c"
0040A092  |.  52   |PUSH EDX

-----------------------------------------------------------------------------------------
0040A079  |.  E8 2>|CALL CCProxy.0043FBA9,這裡跟進,來到這裡:
-----------------------------------------------------------------------------------------
0043FBA9  /$  FF74>PUSH DWORD PTR SS:[ESP+4]       ;  [ESP+4]=902
0043FBAD  |.  E8 6>CALL CCProxy.0043FB1E           ;  跟進
0043FBB2  |.  59   POP ECX
0043FBB3  \.  C3   RETN

-----------------------------------------------------------------------------------------
來自0043FBAD:

0043FB1E  /$  53   PUSH EBX                        ;  EBX=密文902901900
0043FB1F  |.  55   PUSH EBP                        ;  EBP=0
0043FB20  |.  56   PUSH ESI                        ;  ESI=0x12A7A6
0043FB21  |.  57   PUSH EDI                        ;  EDI=0x12CBAE
0043FB22  |.  8B7C>MOV EDI,DWORD PTR SS:[ESP+14]   ;  [ESP+14]單個字元902
0043FB26  |>  833D>/CMP DWORD PTR DS:[477860],1    ;  [477860]=1的值同1比較
0043FB2D  |.  7E 0>|JLE SHORT CCProxy.0043FB3E     ;  等於,所以跳走
0043FB2F  |.  0FB6>|MOVZX EAX,BYTE PTR DS:[EDI]
0043FB32  |.  6A 0>|PUSH 8
0043FB34  |.  50   |PUSH EAX
0043FB35  |.  E8 F>|CALL CCProxy.00445339
0043FB3A  |.  59   |POP ECX
0043FB3B  |.  59   |POP ECX
0043FB3C  |.  EB 0>|JMP SHORT CCProxy.0043FB4D
0043FB3E  |>  0FB6>|MOVZX EAX,BYTE PTR DS:[EDI]    ;  [EDI]=902,單個字元9的ASCII碼39送入EAX
0043FB41  |.  8B0D>|MOV ECX,DWORD PTR DS:[477210]  ;  CCProxy.0047721A,這裡存放一張輔助表
0043FB47  |.  8A04>|MOV AL,BYTE PTR DS:[ECX+EAX*2] ;  [0x47721A+39*2]=00100084,讀取表中內容
0043FB4A  |.  83E0>|AND EAX,8                      ;  (0x84 and 8)= 0
0043FB4D  |>  85C0 |TEST EAX,EAX
0043FB4F  |.  74 0>|JE SHORT CCProxy.0043FB54      ;  EAX=0,所以跳走
0043FB51  |.  47   |INC EDI
0043FB52  |.^ EB D>\JMP SHORT CCProxy.0043FB26
0043FB54  |>  0FB6>MOVZX ESI,BYTE PTR DS:[EDI]     ;  [EDI]=902,單個字元9的ASCII碼39送入ESI
0043FB57  |.  47   INC EDI                         ;  EDI指標前移,指向02
0043FB58  |.  83FE>CMP ESI,2D                      ;  0x39同0x2D("-")比較
0043FB5B  |.  8BEE MOV EBP,ESI                     ;  ESI=39h
0043FB5D  |.  74 0>JE SHORT CCProxy.0043FB64
0043FB5F  |.  83FE>CMP ESI,2B                      ;  39同("+")比較
0043FB62  |.  75 0>JNZ SHORT CCProxy.0043FB68
0043FB64  |>  0FB6>MOVZX ESI,BYTE PTR DS:[EDI]
0043FB67  |.  47   INC EDI
0043FB68  |>  33DB XOR EBX,EBX                     ;  EBX=密文902901900
0043FB6A  |>  833D>/CMP DWORD PTR DS:[477860],1    ;  [477860]=1,同1比較,搜尋[477860],沒發現往

其中寫其他值的地方,好象其始終是1
0043FB71  |.  7E 0>|JLE SHORT CCProxy.0043FB7F     ;  相等,所以跳
0043FB73  |.  6A 0>|PUSH 4
0043FB75  |.  56   |PUSH ESI
0043FB76  |.  E8 B>|CALL CCProxy.00445339
0043FB7B  |.  59   |POP ECX
0043FB7C  |.  59   |POP ECX
0043FB7D  |.  EB 0>|JMP SHORT CCProxy.0043FB8A
0043FB7F  |>  A1 1>|MOV EAX,DWORD PTR DS:[477210]  ;  [477210]=0x47721A,從這開始是一張表
0043FB84  |.  8A04>|MOV AL,BYTE PTR DS:[EAX+ESI*2] ;  [0x47721A+39*2],39為"902"中"9"的ASCII碼
0043FB87  |.  83E0>|AND EAX,4                      ;  477284 and 4,EAX=4
0043FB8A  |>  85C0 |TEST EAX,EAX                   ;  如果EAX=0,認為密文計算結束
0043FB8C  |.  74 0>|JE SHORT CCProxy.0043FB9B
0043FB8E  |.  8D04>|LEA EAX,DWORD PTR DS:[EBX+EBX*>;  EBX=0,第2遍EBX=9,第3遍EBX=5A
0043FB91  |.  8D5C>|LEA EBX,DWORD PTR DS:[ESI+EAX*>;  [39+0*2-30]=9,第2遍[30+2D*2-30]=5A,第3次

[32+5A*2-30]=386,每次迴圈都以計算出的EBX為下一次迴圈的關鍵值
0043FB95  |.  0FB6>|MOVZX ESI,BYTE PTR DS:[EDI]    ;  將第二個字元0送入ESI,第2遍將第3個字元32送

入ESI
0043FB98  |.  47   |INC EDI                        ;  EDI指標前移
0043FB99  |.^ EB C>\JMP SHORT CCProxy.0043FB6A
0043FB9B  |>  83FD>CMP EBP,2D                      ;  EBP=39
0043FB9E  |.  8BC3 MOV EAX,EBX                     ;  EBX=386,上面迴圈的計算結果
0043FBA0  |.  75 0>JNZ SHORT CCProxy.0043FBA4
0043FBA2  |.  F7D8 NEG EAX
0043FBA4  |>  5F   POP EDI
0043FBA5  |.  5E   POP ESI
0043FBA6  |.  5D   POP EBP
0043FBA7  |.  5B   POP EBX
0043FBA8  \.  C3   RETN

-----------------------------------------------------------------------------------------
執行完上面的函式之後返回到這裡:
-----------------------------------------------------------------------------------------
0040A079  |.  E8 2>|CALL CCProxy.0043FBA9          ;  單個字元解密,返回到下面這條語句
0040A07E  |.  B9 E>|MOV ECX,3E7                    ;  0x3E7送入ECX,
0040A083  |.  8D94>|LEA EDX,DWORD PTR SS:[ESP+1018>;  堆疊地址[ESP+1018]=0x12B7A0
0040A08A  |.  2BC8 |SUB ECX,EAX                    ;  3E7-386=61,61為"a"的ASCII碼,單個字元解密

完畢
0040A08C  |.  51   |PUSH ECX                       ;  此處即為解密結果
0040A08D  |.  68 E>|PUSH CCProxy.004730E0          ;  ASCII "%c"
0040A092  |.  52   |PUSH EDX


-----------------------------------------------------------------------------------------
  好了,以上就是密文解密的全部過程,加密是個逆過程,不去管他了,如果你有興趣可以自己去研究

一下。

整理:

  密文是這樣的格式:單個字元轉換為3個數字的密文,所以迴圈取3位密文送到解密函式

解密。解密過程如下,C語言表述:

------------------------------------------------------------------------------------------
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"

void DecryptString(char *pchEnString, unsigned short *pDeCode)
{
  int i;
  unsigned short dwTemp01; 
  unsigned short dwTemp02 = 0;  
  for (i = 0; i < 3; i++, pchEnString++)
  {
    dwTemp01 = dwTemp02 + (dwTemp02 * 4);
    dwTemp02 = *pchEnString + (dwTemp01 * 2) - 0x30;
  }
  *pDeCode = dwTemp02;
}

int main(int argc, char* argv[])
{
  char chEnString[128];
  // 獲取密文
  printf("Please input Encryped string\n");
  scanf("%s", chEnString);
  
  int nKeyCount;
  int nEnStringCount = 0;
  int i;
  for (i = 0; i < 128; i++)
  {
    if ('\0' == chEnString[i])
    {
      break;
    }
    nEnStringCount++;
  }
  nKeyCount = nEnStringCount / 3;

  unsigned int *pdwSingleEnStr = (unsigned int *)malloc(sizeof(unsigned int) * nKeyCount);  

 // Memory 01
  char *p = chEnString;
  for (i = 0; i < nKeyCount; i++)
  {
    pdwSingleEnStr[i] = (unsigned int)p;
    p += 3;
  }

  unsigned short dwDecode[1];
  char chSourceKey[128] = {0};
  for (i = 0; i < nKeyCount; i++)
  {
    DecryptString((char *)pdwSingleEnStr[i], dwDecode);
    
    dwDecode[0] = 0x3E7 - dwDecode[0];
    chSourceKey[i] = (char)dwDecode[0];
  }

  if (pdwSingleEnStr != NULL)                 // release Memory 01
  {
    free(pdwSingleEnStr);
    pdwSingleEnStr = NULL;
  }

  printf("Source Key: %s\n", chSourceKey);

  return 0;
}

為了方便大家,我用VC寫了一個WIN32的CCProxy密文解密器,不是序號產生器哦,請大家測試。
------------------------------------------------------------------------------------------
  以上是菜鳥學習演算法分析的一個學習過程,所以拿簡單的來開刀,希望也能讓更多的像我一樣小菜們

加入演算法分析的行列中來,如有失誤,請大俠指教。

  菜鳥寫菜文。

                          prince   2005.01.23

相關文章