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

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

htg 活跃值
4
2019-6-17 21:38
3541
工具: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后,复原。

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

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

三、主要源代码分析过程(流程):
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
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处。
.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
F5分析伪代码
signed int __cdecl sub_4010E0(int a1)//a1为输入字符串,16字节
{
  signed int v1; // eax
  char v2; // cl
  signed int v3; // ecx
  signed int v4; // eax
  signed int v5; // eax
  signed int v6; // esi
  signed int v7; // ecx
  __int16 v8; // dx
  char *v9; // edi
  __int16 v10; // ax
  signed int v11; // eax
  signed int v12; // ecx
  unsigned __int16 v13; // bx
  signed int v14; // esi
  signed int v15; // ecx
  __int16 v16; // dx
  char *v17; // edi
  __int16 v18; // ax
  signed int v19; // eax
  signed int v20; // ecx
  unsigned __int16 v21; // bx
  unsigned int v22; // eax
  signed int v23; // ecx
  unsigned __int16 v24; // dx
  char v25; // dl
  signed int v26; // eax
  __int16 v27; // si
  int v28; // eax
  struc_1 v30; // [esp+8h] [ebp-90h]
  int v31; // [esp+1Ch] [ebp-7Ch]
  int v32; // [esp+20h] [ebp-78h]
  int v33; // [esp+24h] [ebp-74h]
  int v34[2]; // [esp+28h] [ebp-70h]
  int v35[4]; // [esp+30h] [ebp-68h]
  int v36[2]; // [esp+40h] [ebp-58h]
  struc_1 v37; // [esp+48h] [ebp-50h]
  struc_1 v38; // [esp+5Ch] [ebp-3Ch]
  struc_1 v39; // [esp+70h] [ebp-28h]
  struc_1 v40; // [esp+84h] [ebp-14h]

  v30.intArray[1] = 0x646E9881;
  v1 = 0;
  v30.intArray[0] = 0xE38C9616;
  v30.intArray[2] = 0x81DC0884;
  v30.intArray[3] = 0x4F484DBE;
  *(_DWORD *)&v30.charPtr = 0;
  v31 = 0;
  v32 = 0;
  v33 = 0;
  v34[0] = 0;
  v34[1] = 0;
  v36[0] = 0;
  v36[1] = 0;
  do
  {
    v2 = *((_BYTE *)&v30.intArray[2] + v1) ^ *(_BYTE *)(a1 + v1 + 8);
    *((_BYTE *)v34 + v1) = *((_BYTE *)v30.intArray + v1) ^ *((_BYTE *)v30.intArray + v1 + a1 - (_DWORD)&v30);
    *((_BYTE *)v36 + v1++) = v2;
  }//v34存放前8个字节异或结果;//v36存放后8个字节异或结果
  while ( v1 < 8 );
  v30.intArray[0] = 0;
  v39.intArray[0] = 0;
  v39.intArray[1] = 0;
  v39.intArray[2] = 0;
  v39.intArray[3] = 0;
  v39.charPtr = 0;
  v40.intArray[0] = 0;
  v40.intArray[1] = 0;
  v40.intArray[2] = 0;
  v40.intArray[3] = 0;
  v40.charPtr = 0;
  v37.intArray[0] = 0;
  v37.intArray[1] = 0;
  v37.intArray[2] = 0;
  v37.intArray[3] = 0;
  v37.charPtr = 0;
  v38.intArray[0] = 0;
  v38.intArray[1] = 0;
  v38.intArray[2] = 0;
  v38.intArray[3] = 0;
  v38.charPtr = 0;
  v30.intArray[1] = 0;
  v30.intArray[2] = 0;
  v30.intArray[3] = 0;
  v30.charPtr = 0;
  v3 = 8;
  LOBYTE(v30.intArray[0]) = 8;//v30=8
  v4 = 7;
  do
  {
    if ( *((_BYTE *)v34 + v4) )//异或后字节不能为00,避免多解
      break;
    --v3;
    --v4;
  }
  while ( v4 >= 0 );
  if ( v3 == 8 )
  {
    v5 = 7;
    do
    {
      if ( *((_BYTE *)v36 + v5) )//异或后字节不能为00,避免多解
        break;
      --v3;
      --v5;
    }
    while ( v5 >= 0 );
    if ( v3 == 8 && !(v34[1] & 0xF0000000) )//第7个字节(0开始计数)智能为a-o;貌似没有意义。可能是作者辅助添加去重措施,其实后面有一个解,其有不可输入字符,估计就排除了。
    {
      v6 = 0;
      do
      {
        v35[0] = 0;
        v35[1] = 0;
        v35[2] = 0;
        v35[3] = 0;
        v7 = 0;
        v8 = *((unsigned __int8 *)v34 + v6);
        v9 = (char *)v35 + v6;
        do
        {
          v10 = *((unsigned __int8 *)&v35[2] + v6) + v8 * *((unsigned __int8 *)v34 + v7);
          v9[v7] = *((_BYTE *)&v35[2] + v6) + v8 * *((_BYTE *)v34 + v7);
          ++v7;
          *((_BYTE *)&v35[2] + v6) = HIBYTE(v10);
        }
        while ( v7 < 8 );
        LOBYTE(v11) = 0;
        v12 = 0;
        do
        {
          v13 = (char)v11 + *((unsigned __int8 *)v39.intArray + v12 + v6) + (unsigned __int8)v9[v12];
          *((_BYTE *)v39.intArray + v12++ + v6) = v13;
          v11 = (signed int)v13 >> 8;
        }
        while ( v12 < 9 );
        ++v6;
      }
      while ( v6 < 8 );//执行完了后,v39=X^2(X、Y为分别为前、后8个字节异或后的整数)
      v14 = 0;
      do
      {
        v35[0] = 0;
        v35[1] = 0;
        v35[2] = 0;
        v35[3] = 0;
        v15 = 0;
        v16 = *((unsigned __int8 *)v36 + v14);
        v17 = (char *)v35 + v14;
        do
        {
          v18 = *((unsigned __int8 *)&v35[2] + v14) + v16 * *((unsigned __int8 *)v36 + v15);
          v17[v15] = *((_BYTE *)&v35[2] + v14) + v16 * *((_BYTE *)v36 + v15);
          ++v15;
          *((_BYTE *)&v35[2] + v14) = HIBYTE(v18);
        }
        while ( v15 < 8 );
        LOBYTE(v19) = 0;
        v20 = 0;
        do
        {
          v21 = (char)v19 + *((unsigned __int8 *)v40.intArray + v20 + v14) + (unsigned __int8)v17[v20];
          *((_BYTE *)v40.intArray + v20++ + v14) = v21;
          v19 = (signed int)v21 >> 8;
        }
        while ( v20 < 9 );
        ++v14;
      }
      while ( v14 < 8 );//执行完了后,v40=Y^2(X、Y为分别为前、后8个字节异或后的整数)
      LOBYTE(v22) = v37.charPtr;
      v23 = 0;
      do
      {
        v24 = (unsigned __int8)v22 + 7 * *((unsigned __int8 *)v40.intArray + v23);
        *((_BYTE *)v37.intArray + v23++) = v24;
        v22 = (unsigned int)v24 >> 8;
      }
      while ( v23 < 17 );////执行完了后,v37=7*Y^2(X、Y为分别为前、后8个字节异或后的整数)
      v37.charPtr = HIBYTE(v24);
      v25 = 0;
      v26 = 0;
      do
      {
        v27 = *((unsigned __int8 *)v39.intArray + v26) - *((unsigned __int8 *)v37.intArray + v26) - v25;
        *((_BYTE *)v38.intArray + v26) = v27;
        if ( v27 < 0 )
          v25 = 1;
        ++v26;
      }
      while ( v26 < 17 );///执行完了后,v38=X^2 - 7*Y^2(X、Y为分别为前、后8个字节异或后的整数)
      if ( !v25 )
      {
        v28 = 0;
        while ( *((_BYTE *)v38.intArray + v28) == *((_BYTE *)v30.intArray + v28) )
        {
          if ( ++v28 >= 17 )
            return 1;
        }//判断方程X^2 - 7*Y^2 = 8,那么就要求解 X 和 Y
      }
    }
  }
  return 0;
}
5、求解X^2 - 7*Y^2 = 8,并反推字符串序列号
# -*- coding: UTF-8 -*-
import re
import array

#丢番图方程 X^2 - D * Y^2 = M
#丢番图方程 X^2 - 7 * Y^2 = 8
#通解( 6 + 2 * sqrt(7) )( 8 + 3 * sqrt(7) )^n

#丢番图初始化参数:
A = 6;
B = 2;
C = 8;
D = 3;
#-----------------------------------------------------------------------------------------
# 计算丢番图方程参数:关键代码
def getArg(arg):
	return [arg[0] * C + arg[1] * D * 7,arg[0] * D  +arg[1] * C];
#-----------------------------------------------------------------------------------------
# 字符串转十六进制
def str_to_hex(s):
    return ' '.join([hex(ord(c)).replace('0x', '') for c in s])
#-----------------------------------------------------------------------------------------
def str_to_hexArr(s):
	return re.findall(r'.{2}', s).reverse();
#-----------------------------------------------------------------------------------------
#十六进制数(字符串) 转换成 十六进制数组(十六进制数)(按小端存放)
def hex_to_hexArr(s):
	tmp = ("%s"%(s))[2:len(s)-1]
	#print tmp;
	if len(tmp)%2==1 :
		tmp="0"+tmp;
	tmpArr = re.findall(r'.{2}', tmp);
	tmpArr.reverse();
	#print tmpArr;
	argAHexArr = [];
	for item in tmpArr:
		argAHexArr.append(int(item,16));
	return argAHexArr;
#-----------------------------------------------------------------------------------------
#输出十六进制数组
def print_hexArr_1D(arr):
	hex_array=[];
	for item in arr:
		hex_array.append('0x%02X'%item);
	return hex_array ;
def print_hexArr_2D(arr):
	hex_array=[];
	for item in arr:
		hex_array.append( print_hexArr_1D(item));
	return  hex_array;
#-----------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------
#关键子程序,对找到的解,进行校核判断
def Solution(arg):
	print "\n进一步验证是否满足要求";
	argHex = [hex(arg[0]),hex(arg[1])];
	argHexArr = [hex_to_hexArr(hex(arg[0])),hex_to_hexArr(hex(arg[1]))];
	print "Result for argHexArr_Solution:\n %s"%(argHexArr);
	print "Result for argHexArr_Solution(Hex):\n %s\n"%(print_hexArr_2D(argHexArr));
	#print "-"*80;
	if len(argHexArr)!=2 or len(argHexArr[0])<8 or len(argHexArr[1])<8 :
		print '不满足要求:长度不够(不然高位将为00)';
		print "-"*80;
		return;	
	for item in argHexArr:
		for itm in item:
			if itm == 0 :
				print '不满足要求:不能为00';
				print "-"*80;
				return;	
	#异或运算
	strHexArr = [];
	i=0;
	while i<2:
		j=0;
		tmpHexArr =[];
		while j<8:
			tmpHexArr.append(argHexArr[i][j] ^ keyArr[i][j]);
			j=j+1;
		strHexArr.append(tmpHexArr);
		i=i+1;
	print "Result for strHexArr:\n %s"%(strHexArr);
	print "Result for strHexArr(Hex):\n %s"%(print_hexArr_2D(strHexArr));
	#验证所有字符:应为可输入字符:0x20-0x7E。
	for item in strHexArr:
		for itm in item:
			if itm < 0x20 or itm > 0x7E :
				print '不满足要求:应为可输入字符:0x20-0x7E';
				print "-"*80;
				return;	
	print "找到序列号:";
	#sn = str.decode(strHexArr[0]);
	#sn='---'.join(strHexArr[0])
	sn="";
	for item in strHexArr:
		for itm in item:
			sn=sn+chr(itm);
	print sn;
	sn_result.append(sn);	
	print "-"*80;
	return;
#-----------------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------------
# 求解 大整数:Main主函数,找到潜在的解,判断解,输出解

#key按小端存放
key0 = 0xE38C9616;
key1 = 0x646E9881;
key2 = 0x81DC0884;
key3 = 0x4F484DBE;
sn_result=[];
key = [hex(key0 ^ (key1<<32)),hex(key2 ^ (key3<<32))];
keyArr = [hex_to_hexArr(key[0]),hex_to_hexArr(key[1])];
print "Result for keyArr:\n %s\n"%(keyArr);
print "Result for keyArr(Hex):\n %s"%(print_hexArr_2D(keyArr));
print "-"*80;
arg = [A,B];
argHex =[0x00,0x00];
while arg[0] < 0x1000000000000000 :#第8个字节应为01至0F,才能满足要求
	arg =getArg(arg);
	print "Result for Solution(Hex):\n %s"%(print_hexArr_1D(arg));
	if arg[0] <0x0100000000000000 :
		print "长度不满足要求";
		print "-"*80;
		continue;
	print "长度初步满足要求";
	Solution(arg);
print "-"*80;
print "最终找的结果是:%d个"%(len(sn_result));
print sn_result;
#-----------------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------------
6、运算结果
Result for keyArr:
 [[22, 150, 140, 227, 129, 152, 110, 100], [132, 8, 220, 129, 190, 77, 72, 79]]

Result for keyArr(Hex):
 [['0x16', '0x96', '0x8C', '0xE3', '0x81', '0x98', '0x6E', '0x64'], ['0x84', '0x
08', '0xDC', '0x81', '0xBE', '0x4D', '0x48', '0x4F']]
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x5A', '0x22']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x59A', '0x21E']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x5946', '0x21BE']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x58EC6', '0x219C2']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x58931A', '0x217A62']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x583A2DA', '0x2158C5E']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x57E19A86', '0x21374B7E']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x578960586', '0x2115F2B82']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x57317EBDDA', '0x20F4BB6CA2']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x56D9F55D81A', '0x20D3A579E9E']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x5682C3DEC3C6', '0x20B2B0BE7D3E']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x562BE9E966446', '0x2091DD1903542']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x55D5672587809A', '0x20712A6844D6E2']
长度不满足要求
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x557F3B3B9E1A55A', '0x2050988B2BD38DE']
长度初步满足要求

进一步验证是否满足要求
Result for argHexArr_Solution:
 [[90, 165, 225, 185, 179, 243, 87, 5], [222, 56, 189, 178, 136, 9, 5, 2]]
Result for argHexArr_Solution(Hex):
 [['0x5A', '0xA5', '0xE1', '0xB9', '0xB3', '0xF3', '0x57', '0x05'], ['0xDE', '0x
38', '0xBD', '0xB2', '0x88', '0x09', '0x05', '0x02']]

Result for strHexArr:
 [[76, 51, 109, 90, 50, 107, 57, 97], [90, 48, 97, 51, 54, 68, 77, 77]]
Result for strHexArr(Hex):
 [['0x4C', '0x33', '0x6D', '0x5A', '0x32', '0x6B', '0x39', '0x61'], ['0x5A', '0x
30', '0x61', '0x33', '0x36', '0x44', '0x4D', '0x4D']]
找到序列号:
L3mZ2k9aZ0a36DMM
--------------------------------------------------------------------------------

Result for Solution(Hex):
 ['0x552965D47892D506', '0x20302760C38EB6FE']
长度初步满足要求

进一步验证是否满足要求
Result for argHexArr_Solution:
 [[6, 213, 146, 120, 212, 101, 41, 85], [254, 182, 142, 195, 96, 39, 48, 32]]
Result for argHexArr_Solution(Hex):
 [['0x06', '0xD5', '0x92', '0x78', '0xD4', '0x65', '0x29', '0x55'], ['0xFE', '0x
B6', '0x8E', '0xC3', '0x60', '0x27', '0x30', '0x20']]

Result for strHexArr:
 [[16, 67, 30, 155, 85, 253, 71, 49], [122, 190, 82, 66, 222, 106, 120, 111]]
Result for strHexArr(Hex):
 [['0x10', '0x43', '0x1E', '0x9B', '0x55', '0xFD', '0x47', '0x31'], ['0x7A', '0x
BE', '0x52', '0x42', '0xDE', '0x6A', '0x78', '0x6F']]
不满足要求:应为可输入字符:0x20-0x7E
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

最终找的结果是:1个
['L3mZ2k9aZ0a36DMM']

请按任意键继续. . .

后记:
关于如何找到 丢番图  X^2 - 7*Y^2 = 8的最小正整数解,我的方法是 用Excel来搞定。因为这个方程不复杂,很快就能找到,如果作者整个复杂的角色,估计就麻烦了。比如X^2 - 1141 * Y^2 =1,它的基本解Xn+Yn*sqrt(1141)中的Yn=30693385322765657197397208,这就麻烦了。如果好好设计系数D和M,将增强解密的难度。

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

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