逆向-第三次实验-注册码分析

发布时间 2023-04-24 11:04:39作者: 逆世混沌

本次实验考虑使用到了ida

在使用ida时,用ida32而非64,否则无法查看伪代码。

打开后看到dialog,即对话框元素函数,很有可能是我们要考虑的地方,点击后F5得到伪代码。

 代码

INT_PTR __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
  HICON IconA; // eax
  UINT DlgItemTextA; // eax
  UINT v7; // [esp-4h] [ebp-8h]

  if ( a2 == 272 )
  {
    IconA = LoadIconA(hInstance, (LPCSTR)0x1F4);
    SendMessageA(hWnd, 0x80u, 0, (LPARAM)IconA);
    return 0;
  }
  if ( a2 == 16 )
  {
LABEL_16:
    EndDialog(hWnd, 0);
    return 0;
  }
  if ( a2 != 273 )
    return 0;
  if ( a3 == 300 )
  {
    MessageBoxA(hWnd, Text, Caption, 0);
    return 0;
  }
  if ( a3 != 900 )
  {
    if ( a3 != 400 )
      return 0;
    goto LABEL_16;
  }
  DlgItemTextA = GetDlgItemTextA(hWnd, 100, String1, 300);
  if ( !DlgItemTextA )
    return MessageBoxA(0, aYourNamePlease, aOoohInputError, 0);
  v7 = DlgItemTextA;
  if ( !GetDlgItemTextA(hWnd, 200, byte_409CF8, 300) )
    return MessageBoxA(0, aWhereIsDaSeria, aOoohInputError, 0);
  lstrcatA(String1, String2);
  sub_401000(String1, v7, &unk_4056A8);
  sub_401B79();
  if ( lstrcmpA(byte_409CF8, byte_4079D0) )
  {
    MessageBoxA(0, aHmmmNotLikeThi, aFatalError, 0);
    return 0;
  }
  MessageBoxA(0, aGoodSerialNowS, aGoodWork, 0);
  return 0;
}

 

我们解读一下,逆向的思路是从后面解读:

if ( lstrcmpA(byte_409CF8, byte_4079D0) )
  {
    MessageBoxA(0, aHmmmNotLikeThi, aFatalError, 0);
    return 0;
  }
  MessageBoxA(0, aGoodSerialNowS, aGoodWork, 0);
//这段代码指istrcmpA函数判断byte_409CF8, byte_4079D0是否相等,不相等就fail,相等在下一步就有goodserial

 

 接着来看全部的代码

DlgItemTextA = GetDlgItemTextA(hWnd, 100, String1, 300);  
//此行从对话框hWnd的ID为100的控件中获取输入,并将其存储在String1中,最大长度为300个字符。GetDlgItemTextA()函数的返回值存储在DlgItemTextA中。
//我们大约可以猜测string1是用户名
if ( !DlgItemTextA ) return MessageBoxA(0, aYourNamePlease, aOoohInputError, 0); //如果GetDlgItemTextA()返回NULL,则显示错误消息框,提示输入名称。 v7 = DlgItemTextA; //将DlgItemTextA的值(刚获取的输入)存储到v7中。 if ( !GetDlgItemTextA(hWnd, 200, byte_409CF8, 300) ) return MessageBoxA(0, aWhereIsDaSeria, aOoohInputError, 0); //从ID为200的控件获取输入并存储在byte_409CF8中,最大长度300个字符。如果获取失败,显示另一个错误消息框。我们大约猜测byte是序列码 lstrcatA(String1, String2); //将String2中的字符串追加到String1的末尾。String1现在包含两个控件的输入值。string2可能是个额外变量不被输入 sub_401000(String1, v7, &dword_4056A8); sub_401B79(); //调用两个子例程sub_401000和sub_401B79,传入String1和v7的值,以及dword_4056A8的地址。我们不知道这两个子例程的功能。
我们并不清楚这sub_401000和sub_401B79是什么,查询一下。

sub_401000:

 发现了四个常量,猜测为md5,

值应该运算在dword里了,因为函数没有输出,只有它有指针

sub_401B79:

int v0; 

v0 = dword_4056A8[1]; 
//v0初始化为dword_4056A8数组的第二个元素的值。我们不知道dword_4056A8的值。

wsprintfA(byte_4079D0, "%.8X", v0 ^ dword_4056A8[0]);
//这将v0与dword_4056A8的第一个元素进行异或运算,并使用wsprintfA()将结果作为8个十六进制字符存储在byte_4079D0中。
v0 ^= 0xFBD0099u;
 
//v0与0xFBD0099u进行异或运算。这会修改v0的值。

wsprintfA(&byte_4079D0[8], "%.8X", v0); 
//然后,v0的值作为8个十六进制字符存储在byte_4079D0的第9-16个字符中。

wsprintfA(&byte_4079D0[16], "%.8X", v0 ^ dword_4056A8[2]);
//v0再与dword_4056A8的第三个元素进行异或运算,结果存储在byte_4079D0的第17-24个字符中。
 
wsprintfA(&byte_4079D0[24], "%.8X", dword_4056A8[3]); 
//最后,dword_4056A8的第四个元素的值存储在byte_4079D0的第25-32个字符中。

 

这里也有dword也证实了我们的猜想

我们现在假设一个用户名“admin”

运行olldbg输入后找到lstrcatA,这里可以找到string2

 也就是总字符为“admin BytePtr[e!]”

然后进行

sub_401000(String1, v7, &dword_4056A8); 

sub_401B79();

然后:

我们只要找到这两个值,就可以直接拿到序列号了,因为最后的判断就这一步,前面都是计算

byte_409CF8, byte_4079D0

代码中是

lstrcmpA(byte_409CF8, byte_4079D0)

基本上找到这个函数,打个断点就好了

 

以admin和1填入之后,点击数据窗口跟随

下面的string1是我输入的数,上面是计算好的值

 

good serial