錦州市廣廈電腦維修|上門維修電腦|上門做系統(tǒng)|0416-3905144熱誠服務,錦州廣廈維修電腦,公司IT外包服務
topFlag1 設為首頁
topFlag3 收藏本站
 
maojin003 首 頁 公司介紹 服務項目 服務報價 維修流程 IT外包服務 服務器維護 技術文章 常見故障
錦州市廣廈電腦維修|上門維修電腦|上門做系統(tǒng)|0416-3905144熱誠服務技術文章
一個ReverseMe的算法分析

作者: 佚名  日期:2017-09-29 15:35:23   來源: 本站整理

前幾天寫到博客的 然后昨天寫了一個和這個很相似的KeygenMe.
ReverseMe:https://www.52pojie.cn/thread-647291-1-1.html
KeygenMe:https://www.52pojie.cn/thread-647830-1-1.html

這個ReverseMe是我一年前寫的,不過現(xiàn)在源代碼丟了而且怎么寫的也忘了。正好昨天逛一個論壇的時候看到了這個ReverseMe,

就順便下載玩了玩(也算是重溫了一下),于是就有了這篇文章。
因為篇幅有限 我就寫寫關鍵的地方。
0x0 尋找算法地址
直接來到main函數(shù)(0x004019B2)處。
程序首先獲取ntdll!ZwContinue函數(shù)的地址,然后保存到0x00417F7C處。

004019BE    68 DC504100     push    004150DC                         ; NtContinue
004019C3    68 E8504100     push    004150E8                         ; n
004019C8    33F6            xor     esi, esi
004019CA    33DB            xor     ebx, ebx
004019CC    C705 787F4100 0>mov     dword ptr [0x417F78], 00412000
004019D6    FF15 04304100   call    dword ptr [<&KERNEL32.GetModuleH>; kernel32.GetModuleHandleW
004019DC    50              push    eax
004019DD    FF15 0C304100   call    dword ptr [<&KERNEL32.GetProcAdd>; kernel32.GetProcAddress
004019E3    68 FC504100     push    004150FC                         ; E
004019E8    A3 7C7F4100     mov     dword ptr [0x417F7C], eax

繼續(xù)往下走,發(fā)現(xiàn)程序設置了CONTEXT結構體然后調(diào)用ZwContinue函數(shù)。

00401ABB    8D05 3D1B4000   lea     eax, dword ptr [0x401B3D]        ; 返回地址
00401AC1    50              push    eax
00401AC2    9C              pushfd
00401AC3    8F45 FC         pop     dword ptr [ebp-0x4]
00401AC6    8B45 FC         mov     eax, dword ptr [ebp-0x4]
00401AC9    8945 F0         mov     dword ptr [ebp-0x10], eax
00401ACC    8965 FC         mov     dword ptr [ebp-0x4], esp
00401ACF    8B45 FC         mov     eax, dword ptr [ebp-0x4]
00401AD2    8945 F4         mov     dword ptr [ebp-0xC], eax
00401AD5    896D FC         mov     dword ptr [ebp-0x4], ebp
00401AD8    8B45 FC         mov     eax, dword ptr [ebp-0x4]
00401ADB    C785 30FFFFFF 0>mov     dword ptr [ebp-0xD0], 0x10007    ; CONTEXT_FULL
00401AE5    8945 E4         mov     dword ptr [ebp-0x1C], eax
00401AE8    A1 547F4100     mov     eax, dword ptr [0x417F54]
00401AED    8945 E8         mov     dword ptr [ebp-0x18], eax        ; Eip
00401AF0    16              push    ss
00401AF1    8F45 FC         pop     dword ptr [ebp-0x4]
00401AF4    8B45 FC         mov     eax, dword ptr [ebp-0x4]
00401AF7    8945 F8         mov     dword ptr [ebp-0x8], eax
00401AFA    0E              push    cs
00401AFB    8F45 FC         pop     dword ptr [ebp-0x4]
00401AFE    8B45 FC         mov     eax, dword ptr [ebp-0x4]
00401B01    8945 EC         mov     dword ptr [ebp-0x14], eax
00401B04    1E              push    ds
00401B05    8F45 FC         pop     dword ptr [ebp-0x4]
00401B08    8B45 FC         mov     eax, dword ptr [ebp-0x4]
00401B0B    8945 C8         mov     dword ptr [ebp-0x38], eax
00401B0E    06              push    es
00401B0F    8F45 FC         pop     dword ptr [ebp-0x4]
00401B12    8B45 FC         mov     eax, dword ptr [ebp-0x4]
00401B15    8945 C4         mov     dword ptr [ebp-0x3C], eax
00401B18    0FA0            push    fs
00401B1A    8F45 FC         pop     dword ptr [ebp-0x4]
00401B1D    8B45 FC         mov     eax, dword ptr [ebp-0x4]
00401B20    8945 C0         mov     dword ptr [ebp-0x40], eax
00401B23    0FA8            push    gs
00401B25    8F45 FC         pop     dword ptr [ebp-0x4]
00401B28    8B45 FC         mov     eax, dword ptr [ebp-0x4]
00401B2B    6A 00           push    0x0
00401B2D    8945 BC         mov     dword ptr [ebp-0x44], eax
00401B30    8D85 30FFFFFF   lea     eax, dword ptr [ebp-0xD0]
00401B36    50              push    eax
00401B37    FF15 7C7F4100   call    dword ptr [0x417F7C]             ; ntdll.ZwContinue
00401B3D    68 3C514100     push    0041513C                         ; pause
00401B42    E8 A9000000     call    00401BF0

在Eip(0x7781656D)下斷,然后F9,分析后容易發(fā)現(xiàn):這個函數(shù)也是一個跳轉函數(shù),其中配置CONTEXT結構體并轉移的代碼如下:

778165E3    A1 547F4100     mov     eax, dword ptr [0x417F54]
778165E8    0105 387B4100   add     dword ptr [0x417B38], eax
778165EE    16              push    ss
778165EF    8F05 4C7B4100   pop     dword ptr [0x417B4C]
778165F5    A1 4C7B4100     mov     eax, dword ptr [0x417B4C]
778165FA    A3 487B4100     mov     dword ptr [0x417B48], eax
778165FF    0E              push    cs
77816600    8F05 4C7B4100   pop     dword ptr [0x417B4C]
77816606    A1 4C7B4100     mov     eax, dword ptr [0x417B4C]
7781660B    A3 3C7B4100     mov     dword ptr [0x417B3C], eax
77816610    1E              push    ds
77816611    8F05 4C7B4100   pop     dword ptr [0x417B4C]
77816617    A1 4C7B4100     mov     eax, dword ptr [0x417B4C]
7781661C    A3 187B4100     mov     dword ptr [0x417B18], eax
77816621    06              push    es
77816622    8F05 4C7B4100   pop     dword ptr [0x417B4C]
77816628    A1 4C7B4100     mov     eax, dword ptr [0x417B4C]
7781662D    A3 147B4100     mov     dword ptr [0x417B14], eax
77816632    0FA0            push    fs
77816634    8F05 4C7B4100   pop     dword ptr [0x417B4C]
7781663A    A1 4C7B4100     mov     eax, dword ptr [0x417B4C]
7781663F    A3 107B4100     mov     dword ptr [0x417B10], eax
77816644    0FA8            push    gs
77816646    8F05 4C7B4100   pop     dword ptr [0x417B4C]
7781664C    A1 4C7B4100     mov     eax, dword ptr [0x417B4C]
77816651    6A 00           push    0x0
77816653    68 807A4100     push    0x417A80
77816658    A3 0C7B4100     mov     dword ptr [0x417B0C], eax
7781665D    FF15 7C7F4100   call    dword ptr [0x417F7C]             ; ntdll.ZwContinue
77816663    90              nop
77816664    FF05 507F4100   inc     dword ptr [0x417F50]

在0x7781665D處下斷,攔截每次的Eip值。
攔截以后發(fā)現(xiàn)幾個有用的函數(shù):

0x00401B6D 接受用戶名(存放在0x00417D50處)
0x00401B8B 接受注冊碼(存放在0x00417B50處)
0x7781668F(函數(shù)地址可變) 檢查用戶名是否是12個字節(jié)
0x778166BE(函數(shù)地址可變) 檢查注冊碼是否是12個字節(jié)
0x00412057 算法部分
0x4123A9 返回結果

0x1 分析算法
來到0x00412057處,簡單看看代碼,發(fā)現(xiàn)一堆push call pop之類的指令,這里我使用IDA的F5插件來分析。
這里寫圖片描述
其中的EncryptData:
這里寫圖片描述

這里僅僅調(diào)用了兩個函數(shù):strlen和sub_401000。
我們目前需要做的就是分析出函數(shù)sub_401000是干什么的。
IDA進入401000處,發(fā)現(xiàn)代碼很簡短。
這里寫圖片描述
這段代碼很簡短,就是not not and,如果用一條指令來描述就是nor指令。
其中,有四個指令可以直接被nor模擬。

not(a) = nor(a,a)
and(a,b) = nor(nor(a,a),nor(b,b)) = nor(not(a),not(b))
or(a,b) = nor(nor(a,b),nor(a,b))
xor(a,b) = nor(nor(nor(a,a),nor(b,b)),nor(a,b)) = nor(and(a,b),nor(a,b))

根據(jù)這個關系 我們嘗試將這段算法給改寫成not and or xor的形式

HRESULT __stdcall Decrypt(PINFORMATIONCARD_CRYPTO_HANDLE hCrypto, BOOL fOAEP, DWORD cbInData, 
PBYTE pInData, DWORD *pcbOutData, PBYTE *ppOutData)
{
  HRESULT result; // eax@1
  unsigned int i; // esi@1
  int ByteOfSerial1; // ST28_4@2
  int ByteOfUsername; // ST28_4@2
  int ByteOfSerial; // ebx@2
  int ByteOfUsername1; // edi@2
  int v12; // ST18_4@2
  int v13; // ST14_4@2
  int v14; // eax@2
  int v15; // eax@2
  int v16; // ST18_4@2
  int v17; // ST14_4@2
  int v18; // ST10_4@2
  int v19; // eax@2
  int v20; // eax@2
  int v21; // eax@2
  int v22; // ST18_4@2
  int v23; // eax@2
  int v24; // eax@2
  int v25; // ST18_4@2
  int v26; // ST14_4@2
  int v27; // ST10_4@2
  int v28; // eax@2
  int v29; // eax@2
  int v30; // ST14_4@2
  int v31; // ST10_4@2
  int v32; // ST0C_4@2
  int v33; // eax@2
  int v34; // eax@2
  int v35; // eax@2
  int v36; // ST14_4@2
  int v37; // eax@2
  int v38; // eax@2
  int v39; // eax@2
  int v40; // ST18_4@2
  int v41; // ST14_4@2
  int v42; // ST10_4@2
  int v43; // eax@2
  int v44; // eax@2
  int v45; // ST14_4@2
  int v46; // ST10_4@2
  int v47; // ST0C_4@2
  int v48; // eax@2
  int v49; // eax@2
  int v50; // eax@2
  int v51; // ST14_4@2
  int v52; // eax@2
  int v53; // eax@2
  int v54; // ST14_4@2
  int v55; // ST10_4@2
  int v56; // ST0C_4@2
  int v57; // eax@2
  int v58; // eax@2
  int v59; // ST10_4@2
  int v60; // ST0C_4@2
  int v61; // ST08_4@2
  int v62; // eax@2
  int v63; // eax@2
  int v64; // eax@2
  int v65; // ST10_4@2
  int v66; // eax@2
  int v67; // eax@2
  int v68; // eax@2
  int v69; // eax@2
  char v70; // al@2
  int v71; // edi@2
  int v72; // ebx@2
  int v73; // ST18_4@2
  int v74; // ST14_4@2
  int v75; // eax@2
  int v76; // eax@2

  // 初始化加密數(shù)據(jù)
  *(_DWORD *)&SuccessfulData = EncryptData[0];
  *((_DWORD *)&SuccessfulData + 1) = EncryptData[1];
  *((_DWORD *)&SuccessfulData + 2) = EncryptData[2];
  *(&SuccessfulData + 12) = LOBYTE(EncryptData[3]);
  result = 0;
  i = 0;
  if ( strlen(UserName) != 0 )
  {
    do
    {
      ByteOfSerial1 = Serial[i];                // Serial[i]
      ByteOfUsername = UserName[i];             // UserName[i]
      ByteOfSerial = Serial[i];                 // Serial[i]
      ByteOfUsername1 = UserName[i];            // UserName[i]
      v12 = nor(ByteOfUsername, ByteOfSerial);
      v13 = nor(ByteOfSerial, ByteOfSerial);
      v14 = nor(ByteOfUsername1, ByteOfUsername1);
      v15 = nor(v14, v13);
      v16 = nor(v15, v12);                      // v10 = UserName[i] xor Serial[i]
      v17 = nor(UserName[i], Serial[i]);
      v18 = nor(ByteOfSerial, ByteOfSerial);
      v19 = nor(ByteOfUsername1, ByteOfUsername1);
      v20 = nor(v19, v18);
      v21 = nor(v20, v17);                      // v15 = UserName[i] xor Serial[i]
      v22 = nor(v21, v16);                      // v16 = not(UserName[i] xor Serial[i])
      v23 = nor(ByteOfUsername1, ByteOfUsername1);
      v24 = nor(v23, v22);                      // v18 = UserName[i] and v15
      v25 = nor(Serial[i], v24);                // v19 = nor(Serial[i],UserName[i] and (UserName[i] xor Serial[i]))
      v26 = nor(UserName[i], Serial[i]);
      v27 = nor(ByteOfSerial, ByteOfSerial);
      v28 = nor(ByteOfUsername1, ByteOfUsername1);
      v29 = nor(v28, v27);
      v30 = nor(v29, v26);                      // v24 = UserName[i] xor Serial[i]
      v31 = nor(UserName[i], Serial[i]);
      v32 = nor(ByteOfSerial, ByteOfSerial);
      v33 = nor(ByteOfUsername1, ByteOfUsername1);
      v34 = nor(v33, v32);
      v35 = nor(v34, v31);                      // v29 = UserName[i] xor Serial[i]
      v36 = nor(v35, v30);                      // v30 = not(UserName[i] xor Serial[i])
      v37 = nor(ByteOfUsername1, ByteOfUsername1);
      v38 = nor(v37, v36);                      // v32 = nor(not(UserName[i]),v30)
      v39 = nor(Serial[i], v38);                // v33 = nor(Serial[i],UserName[i] and (UserName[i] xor Serial[i]))
      v40 = nor(v39, v25);                      // v34 = not(v33)
      v41 = nor(UserName[i], Serial[i]);
      v42 = nor(ByteOfSerial, ByteOfSerial);
      v43 = nor(ByteOfUsername1, ByteOfUsername1);
      v44 = nor(v43, v42);
      v45 = nor(v44, v41);                      // v39 = UserName[i] xor Serial[i]
      v46 = nor(UserName[i], Serial[i]);
      v47 = nor(ByteOfSerial, ByteOfSerial);
      v48 = nor(ByteOfUsername1, ByteOfUsername1);
      v49 = nor(v48, v47);
      v50 = nor(v49, v46);                      // v44 = UserName[i] xor Serial[i]
      v51 = nor(v50, v45);                      // v45 = not(UserName[i] xor Serial[i])
      v52 = nor(ByteOfUsername1, ByteOfUsername1);
      v53 = nor(v52, v51);                      // v47 = UserName[i] and (UserName[i] xor Serial[i])
      v54 = nor(Serial[i], v53);                // v48 = nor(Serial[i],UserName[i] and (UserName[i] xor Serial[i]))
      v55 = nor(UserName[i], Serial[i]);
      v56 = nor(ByteOfSerial, ByteOfSerial);
      v57 = nor(ByteOfUsername1, ByteOfUsername1);
      v58 = nor(v57, v56);
      v59 = nor(v58, v55);                      // v53 = UserName[i] xor Serial[i]
      v60 = nor(UserName[i], Serial[i]);
      v61 = nor(ByteOfSerial, ByteOfSerial);
      v62 = nor(ByteOfUsername1, ByteOfUsername1);
      v63 = nor(v62, v61);
      v64 = nor(v63, v60);                      // v58 = UserName[i] xor Serial[i]
      v65 = nor(v64, v59);                      // v59 = not(v58)
      v66 = nor(ByteOfUsername1, ByteOfUsername1);
      v67 = nor(v66, v65);                      // v61 = UserName[i] and (UserName[i] xor Serial[i])
      v68 = nor(Serial[i], v67);                // v62 = nor(Serial[i],UserName[i] and (UserName[i] xor Serial[i]))
      v69 = nor(v68, v54);                      // v63 = not(v62)
      v70 = nor(v69, v40);                      // v64 = not(v63) -> v64 = v62
      UserName[i] = v70;                        // UserName[i] = v62
      v71 = v70;                                // v65 = v62
      v72 = (unsigned __int8)*(&SuccessfulData + i);// v66 = SuccessfulData[i]
      v73 = nor(v72, v70);
      v74 = nor(v71, v71);
      v75 = nor(v72, v72);
      v76 = nor(v75, v74);                      // v70 = SuccessfulData[i] and v62
      *(&SuccessfulData + i) = nor(v76, v73);   // SuccessfulData[i] = SuccessfulDara[i] xor v62
      result = 0;
      ++i;
    }
    while ( i < strlen(UserName) );
  }
  return result;
}

總結一下算法:

設:用戶名為UserName,注冊碼為Serial,提示信息為SuccessfulData,用戶名和注冊碼的每個字節(jié)的關系為x。
則有:
x = nor(Serial[i],UserName[i] and (UserName[i] xor Serial[i]))
SuccessfulData[i] = SuccessfulData[i] xor x

0x2 注冊機的編寫
知道了算法,這樣就可以寫一個注冊機了。
不過因為算法本身的原因,這個注冊機編寫起來還是有一定難度的。
因為不是所有的用戶名所對應的注冊碼都能被輸入進去,不過又因為算法的關系,導致了x并不是只有一個結果。

根據(jù)這個ReverseMe的成功圖片,成功會輸出"Hello world!",正好是SuccessfulData的長度。
那么將字符串"Hello world!"和SuccessfulData逐位異或,得到新的SuccessfulData如下:

char SuccessfulData[] = {0x80,0x90,0x9A,0x8A,0x8A,0x92,0x80,0xCD,0xCE,0xC8,0x80,0xA0};

注冊機的代碼:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define and &
#define xor ^
#define not ~
int nor(int a,int b)
{
    return not a and not b;
}
int main(void)
{
    char SuccessfulData[] = {0x80,0x90,0x9A,0x8A,0x8A,0x92,0x80,0xCD,0xCE,0xC8,0x80,0xA0};
    char UserName[512];
    char Serial[13] = {0};
    scanf("%s",UserName);
    if(strlen(UserName) != 12)
        return 0;
    for(int i = 0;i < 12;i++)
    {
        if(!(UserName[i] >= 0x21 && UserName[i] <= 0x7F))
            return 0;
    }
    for(int i = 0;i < 12;i++)
    {
ContinueWhile:
        for(Serial[i] = 0x21;Serial[i] <= 0x7E;Serial[i]++) //scanf函數(shù)接受字符串輸入時遇到空格截斷.
        {
            if(nor(Serial[i],UserName[i] and (UserName[i] xor Serial[i])) == SuccessfulData[i])
                goto Next;
        }
        /* 當前用戶名沒有對應的可顯示的注冊碼,嘗試更改用戶名 */
        if(UserName[i] == 0x7E)
            UserName[i] -= (Serial[i] - 0x21);
        else
            UserName[i]++;
        if(UserName[i] == 0x20) //空格截斷
            UserName[i]++;
        goto ContinueWhile;
Next:
        _asm nop
    }
    printf("------------------------\nUserName:[%s]\n",UserName);
    printf("Serial:[%s]\n",Serial);
    system("pause");
    return 0;
}

運行結果如圖所示:
這里寫圖片描述
ReverseMe的下載鏈接:http://pan.baidu.com/s/1gf5YC2B 密碼:y093



熱門文章
  • 機械革命S1 PRO-02 開機不顯示 黑...
  • 聯(lián)想ThinkPad NM-C641上電掉電點不...
  • 三星一體激光打印機SCX-4521F維修...
  • 通過串口命令查看EMMC擦寫次數(shù)和判...
  • IIS 8 開啟 GZIP壓縮來減少網(wǎng)絡請求...
  • 索尼kd-49x7500e背光一半暗且閃爍 ...
  • 樓宇對講門禁讀卡異常維修,讀卡芯...
  • 新款海信電視機始終停留在開機界面...
  • 常見打印機清零步驟
  • 安裝驅動時提示不包含數(shù)字簽名的解...
  • 共享打印機需要密碼的解決方法
  • 圖解Windows 7系統(tǒng)快速共享打印機的...
  • 錦州廣廈電腦上門維修

    報修電話:13840665804  QQ:174984393 (聯(lián)系人:毛先生)   
    E-Mail:174984393@qq.com
    維修中心地址:錦州廣廈電腦城
    ICP備案/許可證號:遼ICP備2023002984號-1
    上門服務區(qū)域: 遼寧錦州市區(qū)
    主要業(yè)務: 修電腦,電腦修理,電腦維護,上門維修電腦,黑屏藍屏死機故障排除,無線上網(wǎng)設置,IT服務外包,局域網(wǎng)組建,ADSL共享上網(wǎng),路由器設置,數(shù)據(jù)恢復,密碼破解,光盤刻錄制作等服務

    技術支持:微軟等
    主站蜘蛛池模板: 少妇无码太爽了不卡在线观看| 野花在线无码视频在线播放| 麻豆AV无码精品一区二区 | 国产精品三级在线观看无码| 中文无码伦av中文字幕| 亚洲日韩精品无码专区加勒比| 免费A级毛片无码A| 精品无码av一区二区三区| 精选观看中文字幕高清无码| 亚洲AV无码AV男人的天堂不卡| 永久免费av无码网站yy| 日韩精品无码人妻一区二区三区| 无码人妻精品一区二区三区东京热 | 亚洲一区二区三区国产精品无码| 真人无码作爱免费视频| 亚洲av午夜精品无码专区| 自慰无码一区二区三区| 毛片亚洲AV无码精品国产午夜| 少妇人妻无码专区视频| 亚洲精品无码成人片久久| 国产精品无码专区在线观看| 国产精品无码专区在线播放| 亚洲精品无码成人| 熟妇人妻无码xxx视频| 亚洲av永久无码天堂网| 亚洲性无码AV中文字幕| 亚洲熟妇无码一区二区三区| 亚洲av无码专区青青草原| 无码人妻丝袜在线视频| 92午夜少妇极品福利无码电影| 无码成A毛片免费| 日韩精品专区AV无码| 无码午夜人妻一区二区三区不卡视频| 岛国无码av不卡一区二区| 中国少妇无码专区| 无码人妻一区二区三区免费看| 亚洲AV无码久久精品成人| 久久久久久亚洲AV无码专区| 亚洲AV无码一区二区三区牛牛| 免费无码A片一区二三区 | 亚洲av日韩av无码黑人|