首页
论坛
专栏
课程

[原创] 第四题:达芬奇密码 WP

2019-6-13 19:54 1480

[原创] 第四题:达芬奇密码 WP

2019-6-13 19:54
1480

第四题:达芬奇密码

ida32载入,找到入口函数

int __thiscall sub_401EA0(CWnd *this)
{
  CWnd *v1; // esi
  int v2; // eax
  WCHAR String; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char v6; // [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;
  String = 0;
  memset(&v5, 0, 0x1FEu);
  v6 = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 1000, &String, 20);
  if ( wcslen(&String) == 16 )
  {
    v2 = 0;
    while ( !(*(&String + v2) & 0xFF00) )
    {
      *(&v6 + v2) = *((_BYTE *)&String + 2 * v2);
      if ( ++v2 >= 16 )
      {
        v8 = 64;
        flOldProtect = 0;
        VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);
        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();
          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);
}

程序逻辑十分简单,首先判断输入字符串长度是否为十六,之后将宽字符转换为字符然后调 VirtualProtect这个API,之后qmemcpy(sub_4010E0, &byte_5647B8, 0x330u);将一段字符复制到sub_4010E0上然后继续用调 VirtualProtect这个API,进入if语句,调用sub_4010E0函数,返回值v10 = 1时正确

 

看似十分复杂,确实非常复杂,静态分析是不可能的,这辈子都不可能了,果断OD动态开调,发现真正对字符串加密就只有if语句中的sub_4010E0函数,即od中的TheDaVin.002A10E0

002A1FAA  |.  8D85 F0FEFFFF lea eax,[local.68]
002A1FB0      50            push eax
002A1FB1      E8 2AF1FFFF   call TheDaVin.002A10E0
002A1FB6  |.  8945 F8       mov [local.2],eax

菜鸡只能逐行看汇编代码,再转换为人类能看懂的语言

test = '???? ???? ???? ????' 
assest (test.len == 16)
table = [0x16,0x96,0x8c,0xe3,0x81,0x98,0x6e,0x64,
         0x84,0x08,0xdc,0x81,0xbe,0x4d,0x48,0x4f]

for i in range(8):
    test[i] ^ table[i] -> [008FEFF4+i]
    test[8+i] ^ table[8+i] -> [008EF00C+i]

&arr1 = 008FEFF4
&arr2 = 008EF00C
assest(arr1.len == 8 and arr2.len == 8)
008FF03C: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
ecx = 0
edi = 008FEFFC
edx = 008FF03C
bx = 0
for i in arr1:
    for j in arr1:
        ax = i*j
        ax += bx
        (ax & 0x00ff) -> [edi + ecx]
        (ax >> 8) -> [edi + 0x08]
        bx = [edi + 0x08]
        ecx++
    ecx = 0
    eax = 0
    for i in range(9):
        eax += [edi + i] + [edx + i]
        (eax & 0x00ff) -> [edx+i]
        eax >>= 8
    ecx = 0
    edi++
    edx++


ecx = 0
edi = 008FEFFC
edx = 008FF050
bx = 0
for i in arr2:
    for j in arr2:
        ax = i*j
        ax += bx
        (ax & 0x00ff) -> [edi + ecx]
        (ax >> 8) -> [edi + 0x08]
        bx = [edi + 0x08]
        ecx++
    ecx = 0
    eax = 0
    for i in range(9):
        eax += [edi + i] + [edx + i]
        (eax & 0x00ff) -> [edx+i]
        eax >>= 8
    ecx = 0
    edi++
    edx++

addr = 008FF050
ss = 008FF014
eax = 0
for i in range(0x11):
    dx = [addr + i]
    dx *= 0x07
    eax += dx
    (eax & 0x00ff) -> [ss + i]
    eax >>= 8
eax -> [addr+0x11]

addl = 008FF03C

sa = 008FF028
dl = 0
for i in range(0x11):
    cx = [ss + i]
    si = [addl + i]
    if i > 0:
        assest(cx == si)
    if i = 0:
        assest(si == cx + 8)
#     si -= cx
#     #cx = dl
#     #si -= cx
#     ecx = si
#     #cl -> [sa + i]
#     (si & 0x0f) -> [sa + i]
#     assest (ecx >= 0)
#     if ecx < 0:
#         dl = 1
#     else:
#         dl = 0

# assest ([sa] == 0x08)
# for i in range(1,11):
#     assest ([sa+i] == 0x00)

仔细一看wtf,就是解一条方程

 

x^2 = 7 * y^2 + 8

 

嗯,双曲线方程,求64位整数解

 

将解和table异或一下就可以得到flag了(flag = x<<64 + y,小端序

 

作为一个数学蒻鶸,这怎么解得出来呢!闲着没事干搜了一下椭圆曲线,发现可以根据小整数解组推出大整数解组?果断爆破

for i in range(0xffff):
    for j in range(0xffff):
        ax = i
        bx = j 
        ax *= ax
        bx *= bx
        bx *= 7
        if ax-bx == 8:
            print hex(i),hex(j),hex(ax),hex(bx)

爆破得到这么几组整数解

0x6 0x2 0x24 0x1c
0x5a 0x22 0x1fa4 0x1f9c
0x59a 0x21e 0x1f60a4 0x1f609c
0x5946 0x21be 0x1f21bf24 0x1f21bf1c

蒻鶸怎么可能看得懂数学原理呢,自己动手找规律完事,依据两组小整数解组就可以理论上求出无穷大的整数解组

 

求解代码

x1 = 0x6
y1 = 0x2
x2 = 0x5a
y2 = 0x22

print hex(x1),hex(y1)
print hex(x2),hex(y2)

for i in range(3,17):
    x3 = x2*0x10 - x1
    y3 = y2*0x10 - y1
    print hex(x3) , hex(y3)
    x1,x2 = x2,x3
    y1,y2 = y2,y3

可以得到63位和64位的解,和table异或一下

0x557f3b3b9e1a55a 0x2050988b2bd38de
0x552965d47892d506 0x20302760c38eb6fe

得到

0x61396b325a6d334c 0x4d4d443633613053
0x3147fd559b1e4310 0x4f484dbe81dc088d

排除第二组解,求出flag

'0x61396b325a6d334c'[2:].decode('hex')[::-1]+'0x4d4d443633613053'[2:].decode('hex')[::-1]

L3mZ2k9aS0a36DMM

 

ps:逆向方面不难,耐心点追踪汇编代码仿佛看源码,主要是最后的解方程



[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最后于 2019-6-17 10:15 被丿feng编辑 ,原因:
最新回复 (2)
htg 1 2019-6-24 22:54
2
0
厉害,直接在OD里跟踪到方程式
ccfer 13 2019-6-24 23:06
3
0
这个解法很机智啊,直接观察出递推关系了: x[n+2] = x[n+1]*16 - x[n]
游客
登录 | 注册 方可回帖
返回