首页
社区
课程
招聘
[原创]第四题 达芬奇密码 by 心学
发表于: 2019-6-17 21:38 4190

[原创]第四题 达芬奇密码 by 心学

htg 活跃值
4
2019-6-17 21:38
4190
工具:IDA、Python、Notepad++、Resource_Hacker

一、题目主要流程:
1、获取用户输入字符串sn:16位
2、解密函数代码sub_4010E0
3、进入 sub_4010E0内
4、将输入字符串sn分割为两个8位字符串,变成两个超大整数sn[0]、sn[1],各8个字节长
5、两个超大整数与内置的两个超大整数异或运算,得到新的两个超大整数 X、Y
6、检测:X、Y内各个字节不能有00存在:目的是为了保证高位字节不能为00,也就是避免了多解的可能
7、检测:第7个字节(从0计算),需为01至0F之间,经过异或运算0x64还原,该输入字节只能为0x60-0x6F:即  ` a b c ^ o
8、检测:X^2 - 7 * Y^2 =8;这个是重点,丢番图方程,通过搜索网页,才知道这个方程解法
9、通过,即为正确字符串,L3mZ2k9aZ0a36DMM

1、还原 sub_4010E0 ,Patch掉主程序,便于静态分析
  1.1、找到关键CALL:004010E0
  1.2、004010E0是由从00567B8拷贝0x330字节
  1.3、00567B8的内容是通过XOR 0xAB算出来的
  1.4、Patch文件,便于静态分析
  1.4.1、修改 XOR 地址处的汇编为90
  1.4.2、修改 00567B8的内容为解密的内容,即算出0xAB后,复原。
  1.1、找到关键CALL:004010E0
  1.2、004010E0是由从00567B8拷贝0x330字节
  1.3、00567B8的内容是通过XOR 0xAB算出来的
  1.4、Patch文件,便于静态分析
  1.4.1、修改 XOR 地址处的汇编为90
  1.4.2、修改 00567B8的内容为解密的内容,即算出0xAB后,复原。

2、学习丢番图方程的通解 X^2 - 7 * Y^2 =8 :找到满足条件的解
具体可以学习丢番图方程的解法,该通解是:( 6 + 2 * sqrt(7) ) ( 8 + 3 *  sqrt(7) )^n;我们可以通过程序来列出在一定范围的解

3、根据上述流程,反推输入字符串

三、主要源代码分析过程(流程):
1、IDA内找到软件入口:
三、主要源代码分析过程(流程):
1、IDA内找到软件入口:
1、IDA内找到软件入口:
    因为是MFC程序,所以我们要找到按钮的触发方法才行
   方法:找到Button等控件的ID,通过 Resource_Hacker查找,打开Dialog表,
102 DIALOGEX 0, 0, 319, 117
STYLE DS_FIXEDSYS | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
EXSTYLE WS_EX_APPWINDOW
CAPTION "SequenceAdventure (CTF2019)"
LANGUAGE LANG_CHINESE, 0x2
FONT 9, "MS Shell Dlg"
{
   CONTROL "Check", 1, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 90, 305, 17 
   CONTROL "", 1000, EDIT, ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 7, 18, 305, 67 
   CONTROL "Please Input The Serial:", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 5, 123, 12 
   CONTROL "Close", 1002, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 241, 1, 50, 14 
}
我们能发现 Button Check的ID为1(估计是作者故意的,搞那么小);附近有一个Close,其ID是1002(0x3EA),我们通过它来找到对应的dialog
102 DIALOGEX 0, 0, 319, 117
STYLE DS_FIXEDSYS | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
EXSTYLE WS_EX_APPWINDOW
CAPTION "SequenceAdventure (CTF2019)"
LANGUAGE LANG_CHINESE, 0x2
FONT 9, "MS Shell Dlg"
{
   CONTROL "Check", 1, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 90, 305, 17 
   CONTROL "", 1000, EDIT, ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 7, 18, 305, 67 
   CONTROL "Please Input The Serial:", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 5, 123, 12 
   CONTROL "Close", 1002, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 241, 1, 50, 14 
}
我们能发现 Button Check的ID为1(估计是作者故意的,搞那么小);附近有一个Close,其ID是1002(0x3EA),我们通过它来找到对应的dialog
IDA:Search 搜索立即数:0x3EA,很快就在.rdata里定位到具体内容
大佬一般看到后,就能很快找到对应的处理方法,我们可以先添加具体的消息处理结果,便于理解,添加两个结构 AFX_MSGMAP_ENTRY和AFX_MSGMAP,主要先后添加:IDA→View→ Sub Views→Local Types:按Insert键,先后插入两个消息定义
struct AFX_MSGMAP_ENTRY
{
	UINT nMessage;
	UINT nCode;
	UINT nID;
	UINT nLastID;
	UINT_PTR nSig;
	void (*pfn)(void);
};
 
struct AFX_MSGMAP
{
  const AFX_MSGMAP *(__stdcall *pfnGetBaseMap)();
  const AFX_MSGMAP_ENTRY *lpEntries;
};
选中刚才定义的消息(拖入到最下面,能看到最新添加的),然后右键,同步到 idb
现在定位到刚才的 .rdata 的0x3EA处。
struct AFX_MSGMAP_ENTRY
{
	UINT nMessage;
	UINT nCode;
	UINT nID;
	UINT nLastID;
	UINT_PTR nSig;
	void (*pfn)(void);
};
 
struct AFX_MSGMAP
{
  const AFX_MSGMAP *(__stdcall *pfnGetBaseMap)();
  const AFX_MSGMAP_ENTRY *lpEntries;
};
选中刚才定义的消息(拖入到最下面,能看到最新添加的),然后右键,同步到 idb
现在定位到刚才的 .rdata 的0x3EA处。
.rdata:005456D8                 db  11h
.rdata:005456D9                 db    1
.rdata:005456DA                 db    0
.rdata:005456DB                 db    0
.rdata:005456DC                 db    0
.rdata:005456DD                 db    0
.rdata:005456DE                 db    0
.rdata:005456DF                 db    0
.rdata:005456E0                 db 0EAh
.rdata:005456E1                 db    3
.rdata:005456E2                 db    0
.rdata:005456E3                 db    0
.rdata:005456E4                 db 0EAh
.rdata:005456E5                 db    3
.rdata:005456E6                 db    0
.rdata:005456E7                 db    0
.rdata:005456E8                 db  39h ; 9
.rdata:005456E9                 db    0
.rdata:005456EA                 db    0
.rdata:005456EB                 db    0
.rdata:005456EC                 dd offset sub_402000
在 .rdata:005456D8   按 Art +Q键盘,选择AFX_MSGMAP_ENTRY, 最后,形成的结构如下所述
.rdata:00545690 stru_545690     AFX_MSGMAP_ENTRY <0Fh, 0, 0, 0, 13h, offset sub_401DE0>
.rdata:00545690                                         ; DATA XREF: .rdata:stru_545708↓o
.rdata:005456A8                 AFX_MSGMAP_ENTRY <37h, 0, 0, 0, 28h, offset sub_401E90>
.rdata:005456C0                 AFX_MSGMAP_ENTRY <111h, 0, 1, 1, 39h, offset sub_401EA0>
.rdata:005456D8                 AFX_MSGMAP_ENTRY <111h, 0, 3EAh, 3EAh, 39h, offset sub_402000>
.rdata:005456F0                 AFX_MSGMAP_ENTRY <0>
.rdata:00545708 stru_545708     AFX_MSGMAP <offset sub_4055EC, offset stru_545690>
然后,我们比对一下刚才在 Resource_Hacker查找的Dialog内容,很容易定位到button的ID为1 ,即check对应的是.rdata:005456C0                 AFX_MSGMAP_ENTRY <111h, 0, 1, 1, 39h, offset sub_401EA0>
,然后我们双击 offset sub_401EA0 进入到该方法,按F5,很容易判断即为button check的处理方法。
int __thiscall btnCheck(CWnd *this)
{
  CWnd *v1; // esi
  int i; // eax
  WCHAR inputStr; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char newInputStr; // [esp+20Ch] [ebp-110h]
  char v7; // [esp+20Dh] [ebp-10Fh]
  DWORD v8; // [esp+30Ch] [ebp-10h]
  CWnd *v9; // [esp+310h] [ebp-Ch]
  int v10; // [esp+314h] [ebp-8h]
  DWORD flOldProtect; // [esp+318h] [ebp-4h]

  v1 = this;
  v9 = this;
  inputStr = 0;
  memset(&v5, 0, 0x1FEu);
  newInputStr = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 1000, &inputStr, 20);
  if ( wcslen(&inputStr) == 16 )                // 输入字符串长度:16
  {
    i = 0;
    while ( !(*(&inputStr + i) & 0xFF00) )      // 字符应该是 0001 至 00FF;不能为 FF00 和 0100 的宽字符 
    {
      *(&newInputStr + i) = *((_BYTE *)&inputStr + 2 * i);
      if ( ++i >= 16 )
      {
        v8 = 0x40;
        flOldProtect = 0;
        VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);// 0x40:PAGE_EXECUTE_READWRITE:内存地址、长度、访问、保存旧的
        if ( GetLastError() )
          return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
        qmemcpy(sub_4010E0, byte_5647B8, 0x330u);
        VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);
        if ( !GetLastError() )
        {
          v10 = 0;
          v10 = sub_4010E0(&newInputStr);
          if ( v10 == 1 )
            return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
        }
        v1 = v9;
        return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
      }
    }
  }
  return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
}

2、分析主函数 sub_401EA0
里面有一个VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);这里有修改
qmemcpy(sub_4010E0, byte_5647B8, 0x330u);
很明显,它将 byte_5647B8内容覆盖了 sub_4010E0,继续跟进 byte_5647B8
.data:005647B8                          ; char byte_5647B8[816]
.data:005647B8 2A                       byte_5647B8     db 2Ah                  ; DATA XREF: btnCheck+E0↑o
.data:005647B9 47                                       db  47h ; G
.data:005647BA 3B                                       db  3Bh ; ;
.data:005647BB AB                                       db 0ABh
.data:005647BC AB                                       db 0ABh
.data:005647BD AB                                       db 0ABh
.data:005647BE FD                                       db 0FDh
.data:005647BF 1B                                       db 1Bh
.data:005647C0 2A                                       db  2Ah ; *
.data:005647C1 FC                                       db 0FCh
.data:005647C2 20                                       db 20h
.data:005647C3 17                                       db  17h
.data:005647B8 2A                      byte_5647B8     db 2Ah                  ; DATA XREF: sub_401D80:loc_401DC0↑w
.data:005647B9 47                                      db  47h ; G
.data:005647BA 3B                                      db  3Bh ; ;
.data:005647BB AB                                      db 0ABh
.data:005647BC AB                                      db 0ABh
.data:005647BD AB                                      db 0ABh
.data:005647BE FD                                      db 0FDh
.data:005647BF 1B                                      db  1Bh
.data:005647C0 2A                                      db  2Ah ; *
.data:005647C1 FC                                      db 0FCh
.data:005647C2 20                                      db  20h
.data:005647C3 17                                      db  17h

很明显,这个不是代码,我们看看有哪些代码访问了它,按x,找到条目(我在原代码做了Patch,其实该代码处有两处引用),一处是check处理;一处是修改 byte_5647B8,我们跟进sub_401D80,查看
signed int __thiscall sub_401D80(CDialog *this)
{
  CDialog *v1; // esi
  unsigned int v2; // eax

  v1 = this;
  CDialog::OnInitDialog(this);
  SendMessageW(*((HWND *)v1 + 8), 0x80u, 1u, *((_DWORD *)v1 + 29));
  SendMessageW(*((HWND *)v1 + 8), 0x80u, 0, *((_DWORD *)v1 + 29));
  v2 = 0;
  do
  {
    byte_5647B8[v2] ^= 0xABu;
    ++v2;
  }
  while ( v2 < 0x330 );
  return 1;
}
它相当于对 byte_5647B8做了异或处理后又保存了,相当于原来进行了加密,现在进行了解密

3、Patch代码:以使其更容易静态分析
我们做两件事:一是通过异或解密覆盖sub_4010E0;二是nop掉赋值语句
3.1、 异或解密覆盖sub_4010E0
使用IDC代码处理
static main(void)
{
  auto fp, begin, end, dexbyte, sourceAdd;
  sourceAdd = 0x5647B8;
  begin = 0x4010E0;
  end = begin + 0x330;
  for ( dexbyte = begin; dexbyte < end; dexbyte ++ , sourceAdd ++  )
  {
	PatchByte(dexbyte,Byte(sourceAdd) ^ 0xAB);
  }
}
3.2、 nop掉赋值语句
.text:00401F8A F3 A5 ===> 90 90//也可以将 text:00401F80- text:00401F8B处均nop  
.text:00401F48 8B 1D 10 D2 51 00                       mov     ebx, ds:VirtualProtect
.text:00401F4E 8D 45 FC                                lea     eax, [ebp+flOldProtect]
.text:00401F51 50                                      push    eax             ; lpflOldProtect
.text:00401F52 6A 40                                   push    40h             ; flNewProtect
.text:00401F54 68 17 0D 00 00                          push    0D17h           ; dwSize
.text:00401F59 68 E0 10 40 00                          push    offset sub_4010E0 ; lpAddress
.text:00401F5E C7 45 F0 40 00 00 00                    mov     [ebp+var_10], 40h
.text:00401F65 C7 45 FC 00 00 00 00                    mov     [ebp+flOldProtect], 0
.text:00401F6C FF D3                                   call    ebx ; VirtualProtect
.text:00401F6E FF 15 08 D4 51 00                       call    ds:GetLastError
.text:00401F74 85 C0                                   test    eax, eax
.text:00401F76 75 62                                   jnz     short loc_401FDA
.text:00401F78 8B 55 FC                                mov     edx, [ebp+flOldProtect]
.text:00401F7B B9 CC 00 00 00                          mov     ecx, 0CCh
.text:00401F80 90                                      nop
.text:00401F81 90                                      nop
.text:00401F82 90                                      nop
.text:00401F83 90                                      nop
.text:00401F84 90                                      nop
.text:00401F85 90                                      nop
.text:00401F86 90                                      nop
.text:00401F87 90                                      nop
.text:00401F88 90                                      nop
.text:00401F89 90                                      nop
.text:00401F8A 90                                      nop
.text:00401F8B 90                                      nop
.text:00401F8C 8D 4D F0                                lea     ecx, [ebp+var_10]
.text:00401F8F 51                                      push    ecx             ; lpflOldProtect
.text:00401F90 52                                      push    edx             ; flNewProtect
.text:00401F91 68 17 0D 00 00                          push    0D17h           ; dwSize
.text:00401F96 68 E0 10 40 00                          push    offset sub_4010E0 ; lpAddress

3.3、保存
IDA:Edit→Patch Program→Assembly

4、静态分析 sub_4010E0
.rdata:005456D8                 db  11h
.rdata:005456D9                 db    1
.rdata:005456DA                 db    0
.rdata:005456DB                 db    0
.rdata:005456DC                 db    0
.rdata:005456DD                 db    0
.rdata:005456DE                 db    0
.rdata:005456DF                 db    0
.rdata:005456E0                 db 0EAh
.rdata:005456E1                 db    3
.rdata:005456E2                 db    0
.rdata:005456E3                 db    0
.rdata:005456E4                 db 0EAh
.rdata:005456E5                 db    3
.rdata:005456E6                 db    0
.rdata:005456E7                 db    0
.rdata:005456E8                 db  39h ; 9
.rdata:005456E9                 db    0
.rdata:005456EA                 db    0
.rdata:005456EB                 db    0
.rdata:005456EC                 dd offset sub_402000
在 .rdata:005456D8   按 Art +Q键盘,选择AFX_MSGMAP_ENTRY, 最后,形成的结构如下所述
.rdata:00545690 stru_545690     AFX_MSGMAP_ENTRY <0Fh, 0, 0, 0, 13h, offset sub_401DE0>
.rdata:00545690                                         ; DATA XREF: .rdata:stru_545708↓o
.rdata:005456A8                 AFX_MSGMAP_ENTRY <37h, 0, 0, 0, 28h, offset sub_401E90>
.rdata:005456C0                 AFX_MSGMAP_ENTRY <111h, 0, 1, 1, 39h, offset sub_401EA0>
.rdata:005456D8                 AFX_MSGMAP_ENTRY <111h, 0, 3EAh, 3EAh, 39h, offset sub_402000>
.rdata:005456F0                 AFX_MSGMAP_ENTRY <0>
.rdata:00545708 stru_545708     AFX_MSGMAP <offset sub_4055EC, offset stru_545690>
然后,我们比对一下刚才在 Resource_Hacker查找的Dialog内容,很容易定位到button的ID为1 ,即check对应的是.rdata:005456C0                 AFX_MSGMAP_ENTRY <111h, 0, 1, 1, 39h, offset sub_401EA0>
,然后我们双击 offset sub_401EA0 进入到该方法,按F5,很容易判断即为button check的处理方法。
int __thiscall btnCheck(CWnd *this)
{
  CWnd *v1; // esi
  int i; // eax
  WCHAR inputStr; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char newInputStr; // [esp+20Ch] [ebp-110h]
  char v7; // [esp+20Dh] [ebp-10Fh]
  DWORD v8; // [esp+30Ch] [ebp-10h]
  CWnd *v9; // [esp+310h] [ebp-Ch]
  int v10; // [esp+314h] [ebp-8h]
  DWORD flOldProtect; // [esp+318h] [ebp-4h]

  v1 = this;
  v9 = this;
  inputStr = 0;
  memset(&v5, 0, 0x1FEu);
  newInputStr = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 1000, &inputStr, 20);
  if ( wcslen(&inputStr) == 16 )                // 输入字符串长度:16
  {
    i = 0;
    while ( !(*(&inputStr + i) & 0xFF00) )      // 字符应该是 0001 至 00FF;不能为 FF00 和 0100 的宽字符 
    {
      *(&newInputStr + i) = *((_BYTE *)&inputStr + 2 * i);
      if ( ++i >= 16 )
      {
        v8 = 0x40;
        flOldProtect = 0;
        VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);// 0x40:PAGE_EXECUTE_READWRITE:内存地址、长度、访问、保存旧的
        if ( GetLastError() )
          return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
        qmemcpy(sub_4010E0, byte_5647B8, 0x330u);
        VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);
        if ( !GetLastError() )
        {
          v10 = 0;
          v10 = sub_4010E0(&newInputStr);
          if ( v10 == 1 )
            return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
        }
        v1 = v9;
        return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
      }
    }
  }
  return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
}

2、分析主函数 sub_401EA0
里面有一个VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);这里有修改
qmemcpy(sub_4010E0, byte_5647B8, 0x330u);
很明显,它将 byte_5647B8内容覆盖了 sub_4010E0,继续跟进 byte_5647B8
.data:005647B8                          ; char byte_5647B8[816]
.data:005647B8 2A                       byte_5647B8     db 2Ah                  ; DATA XREF: btnCheck+E0↑o
.data:005647B9 47                                       db  47h ; G
.data:005647BA 3B                                       db  3Bh ; ;
.data:005647BB AB                                       db 0ABh
.data:005647BC AB                                       db 0ABh
.data:005647BD AB                                       db 0ABh
.data:005647BE FD                                       db 0FDh
.data:005647BF 1B                                       db 1Bh
.data:005647C0 2A                                       db  2Ah ; *
.data:005647C1 FC                                       db 0FCh
.data:005647C2 20                                       db 20h
.data:005647C3 17                                       db  17h
.data:005647B8 2A                      byte_5647B8     db 2Ah                  ; DATA XREF: sub_401D80:loc_401DC0↑w
.data:005647B9 47                                      db  47h ; G
.data:005647BA 3B                                      db  3Bh ; ;
.data:005647BB AB                                      db 0ABh
.data:005647BC AB                                      db 0ABh
.data:005647BD AB                                      db 0ABh
.data:005647BE FD                                      db 0FDh
.data:005647BF 1B                                      db  1Bh
.data:005647C0 2A                                      db  2Ah ; *
.data:005647C1 FC                                      db 0FCh
.data:005647C2 20                                      db  20h
.data:005647C3 17                                      db  17h

很明显,这个不是代码,我们看看有哪些代码访问了它,按x,找到条目(我在原代码做了Patch,其实该代码处有两处引用),一处是check处理;一处是修改 byte_5647B8,我们跟进sub_401D80,查看
signed int __thiscall sub_401D80(CDialog *this)
{
  CDialog *v1; // esi
  unsigned int v2; // eax

  v1 = this;
  CDialog::OnInitDialog(this);
  SendMessageW(*((HWND *)v1 + 8), 0x80u, 1u, *((_DWORD *)v1 + 29));
  SendMessageW(*((HWND *)v1 + 8), 0x80u, 0, *((_DWORD *)v1 + 29));
  v2 = 0;
  do
  {
    byte_5647B8[v2] ^= 0xABu;
    ++v2;
  }
  while ( v2 < 0x330 );
  return 1;
}
它相当于对 byte_5647B8做了异或处理后又保存了,相当于原来进行了加密,现在进行了解密

3、Patch代码:以使其更容易静态分析
我们做两件事:一是通过异或解密覆盖sub_4010E0;二是nop掉赋值语句
3.1、 异或解密覆盖sub_4010E0
使用IDC代码处理
static main(void)
{
  auto fp, begin, end, dexbyte, sourceAdd;
  sourceAdd = 0x5647B8;
  begin = 0x4010E0;
  end = begin + 0x330;
  for ( dexbyte = begin; dexbyte < end; dexbyte ++ , sourceAdd ++  )
  {
	PatchByte(dexbyte,Byte(sourceAdd) ^ 0xAB);
  }
}
3.2、 nop掉赋值语句
.text:00401F8A F3 A5 ===> 90 90//也可以将 text:00401F80- text:00401F8B处均nop  
.text:00401F48 8B 1D 10 D2 51 00                       mov     ebx, ds:VirtualProtect
.text:00401F4E 8D 45 FC                                lea     eax, [ebp+flOldProtect]
.text:00401F51 50                                      push    eax             ; lpflOldProtect
.text:00401F52 6A 40                                   push    40h             ; flNewProtect
.text:00401F54 68 17 0D 00 00                          push    0D17h           ; dwSize
.text:00401F59 68 E0 10 40 00                          push    offset sub_4010E0 ; lpAddress
.text:00401F5E C7 45 F0 40 00 00 00                    mov     [ebp+var_10], 40h
.text:00401F65 C7 45 FC 00 00 00 00                    mov     [ebp+flOldProtect], 0
.text:00401F6C FF D3                                   call    ebx ; VirtualProtect
.text:00401F6E FF 15 08 D4 51 00                       call    ds:GetLastError
.text:00401F74 85 C0                                   test    eax, eax
.text:00401F76 75 62                                   jnz     short loc_401FDA
.text:00401F78 8B 55 FC                                mov     edx, [ebp+flOldProtect]
.text:00401F7B B9 CC 00 00 00                          mov     ecx, 0CCh
.text:00401F80 90                                      nop
.text:00401F81 90                                      nop
.text:00401F82 90                                      nop
.text:00401F83 90                                      nop
.text:00401F84 90                                      nop
.text:00401F85 90                                      nop
.text:00401F86 90                                      nop
.text:00401F87 90                                      nop
.text:00401F88 90                                      nop
.text:00401F89 90                                      nop
.text:00401F8A 90                                      nop
.text:00401F8B 90                                      nop
.text:00401F8C 8D 4D F0                                lea     ecx, [ebp+var_10]
.text:00401F8F 51                                      push    ecx             ; lpflOldProtect
.text:00401F90 52                                      push    edx             ; flNewProtect
.text:00401F91 68 17 0D 00 00                          push    0D17h           ; dwSize
.text:00401F96 68 E0 10 40 00                          push    offset sub_4010E0 ; lpAddress

3.3、保存
IDA:Edit→Patch Program→Assembly

4、静态分析 sub_4010E0
.rdata:00545690 stru_545690     AFX_MSGMAP_ENTRY <0Fh, 0, 0, 0, 13h, offset sub_401DE0>
.rdata:00545690                                         ; DATA XREF: .rdata:stru_545708↓o
.rdata:005456A8                 AFX_MSGMAP_ENTRY <37h, 0, 0, 0, 28h, offset sub_401E90>
.rdata:005456C0                 AFX_MSGMAP_ENTRY <111h, 0, 1, 1, 39h, offset sub_401EA0>
.rdata:005456D8                 AFX_MSGMAP_ENTRY <111h, 0, 3EAh, 3EAh, 39h, offset sub_402000>
.rdata:005456F0                 AFX_MSGMAP_ENTRY <0>
.rdata:00545708 stru_545708     AFX_MSGMAP <offset sub_4055EC, offset stru_545690>
然后,我们比对一下刚才在 Resource_Hacker查找的Dialog内容,很容易定位到button的ID为1 ,即check对应的是.rdata:005456C0                 AFX_MSGMAP_ENTRY <111h, 0, 1, 1, 39h, offset sub_401EA0>
,然后我们双击 offset sub_401EA0 进入到该方法,按F5,很容易判断即为button check的处理方法。
int __thiscall btnCheck(CWnd *this)
{
  CWnd *v1; // esi
  int i; // eax
  WCHAR inputStr; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char newInputStr; // [esp+20Ch] [ebp-110h]
  char v7; // [esp+20Dh] [ebp-10Fh]
  DWORD v8; // [esp+30Ch] [ebp-10h]
  CWnd *v9; // [esp+310h] [ebp-Ch]
  int v10; // [esp+314h] [ebp-8h]
  DWORD flOldProtect; // [esp+318h] [ebp-4h]

  v1 = this;
  v9 = this;
  inputStr = 0;
  memset(&v5, 0, 0x1FEu);
  newInputStr = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 1000, &inputStr, 20);
  if ( wcslen(&inputStr) == 16 )                // 输入字符串长度:16
  {
    i = 0;
    while ( !(*(&inputStr + i) & 0xFF00) )      // 字符应该是 0001 至 00FF;不能为 FF00 和 0100 的宽字符 
    {
      *(&newInputStr + i) = *((_BYTE *)&inputStr + 2 * i);
      if ( ++i >= 16 )
      {
        v8 = 0x40;
        flOldProtect = 0;
        VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);// 0x40:PAGE_EXECUTE_READWRITE:内存地址、长度、访问、保存旧的
        if ( GetLastError() )
          return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
        qmemcpy(sub_4010E0, byte_5647B8, 0x330u);
        VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);
        if ( !GetLastError() )
        {
          v10 = 0;
          v10 = sub_4010E0(&newInputStr);
          if ( v10 == 1 )
            return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
        }
        v1 = v9;
        return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
      }
    }
  }
  return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
}

2、分析主函数 sub_401EA0
int __thiscall btnCheck(CWnd *this)
{
  CWnd *v1; // esi
  int i; // eax
  WCHAR inputStr; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char newInputStr; // [esp+20Ch] [ebp-110h]
  char v7; // [esp+20Dh] [ebp-10Fh]
  DWORD v8; // [esp+30Ch] [ebp-10h]
  CWnd *v9; // [esp+310h] [ebp-Ch]
  int v10; // [esp+314h] [ebp-8h]
  DWORD flOldProtect; // [esp+318h] [ebp-4h]

  v1 = this;
  v9 = this;
  inputStr = 0;
  memset(&v5, 0, 0x1FEu);
  newInputStr = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 1000, &inputStr, 20);
  if ( wcslen(&inputStr) == 16 )                // 输入字符串长度:16
  {
    i = 0;
    while ( !(*(&inputStr + i) & 0xFF00) )      // 字符应该是 0001 至 00FF;不能为 FF00 和 0100 的宽字符 
    {
      *(&newInputStr + i) = *((_BYTE *)&inputStr + 2 * i);
      if ( ++i >= 16 )
      {
        v8 = 0x40;
        flOldProtect = 0;
        VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);// 0x40:PAGE_EXECUTE_READWRITE:内存地址、长度、访问、保存旧的
        if ( GetLastError() )
          return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
        qmemcpy(sub_4010E0, byte_5647B8, 0x330u);
        VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);
        if ( !GetLastError() )
        {
          v10 = 0;
          v10 = sub_4010E0(&newInputStr);
          if ( v10 == 1 )
            return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
        }
        v1 = v9;
        return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
      }
    }
  }
  return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
}

2、分析主函数 sub_401EA0
里面有一个VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);这里有修改
qmemcpy(sub_4010E0, byte_5647B8, 0x330u);

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-6-17 21:49 被htg编辑 ,原因: 修正错误
收藏
免费 3
支持
分享
最新回复 (1)
雪    币: 5568
活跃值: (3208)
能力值: ( LV12,RANK:407 )
在线值:
发帖
回帖
粉丝
2
https://www.wolframalpha.com/这个更厉害。
2019-6-24 13:29
0
游客
登录 | 注册 方可回帖
返回
//