本次实验考虑使用到了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
标签:逆向,return,第三次,4056A8,dword,byte,4079D0,注册码,sub From: https://www.cnblogs.com/nish1hundun/p/17348822.html