2、Afkayas
002---Afkayas.1
简述:
难度:一颗星
保护方式:||Name/Serial(VB5)
操作系统: Windows(95)[I386, 32 位, GUI]
编译器: Microsoft Visual Basic(5.0)
语言: VB
界面
双击打开后是这样的。
直接随便输入一个错误的。
这时候就可以直接拖入x32dbg了
初探
在x32dbg和之前的思路一致,直接跑起来,弹窗后直接使用堆栈回调的方式即可
有以下的汇编,比较有意思 这个如果没有猜错的话,应该就是这个了。首先暴力破解一下
0040258 | 68 801B4000 | push afkayas.1.401B80 | 401B80:L"You Get It"
0040259 | 68 9C1B4000 | push afkayas.1.401B9C | 401B9C:L"\r\n"
0040259 | FFD7 | call edi |
0040259 | 8BD0 | mov edx,eax |
0040259 | 8D4D E8 | lea ecx,dword ptr ss:[ebp-18] |
0040259 | FFD3 | call ebx |
004025A | 50 | push eax |
004025A | 68 A81B4000 | push afkayas.1.401BA8 | 401BA8:L"KeyGen It Now"
在他的上一句je打一个断点
0040258 | 74 58 | je afkayas.1.4025E5 |
004025E | 52 | push edx |
004025E | EB 56 | jmp afkayas.1.40263B |
------------------------------------------------------------------------------
004025E | 68 C81B4000 | push afkayas.1.401BC8 | 401BC8:L"You Get Wrong"
004025E | 68 9C1B4000 | push afkayas.1.401B9C | 401B9C:L"\r\n"
004025E | FFD7 | call edi |
004025F | 8BD0 | mov edx,eax |
004025F | 8D4D E8 | lea ecx,dword ptr ss:[ebp-18] |
004025F | FFD3 | call ebx |
004025F | 50 | push eax |
004025F | 68 E81B4000 | push afkayas.1.401BE8 | 401BE8:L"Try Again"
跳转到了横线的下方,我直接将其nop掉就可以实现破解了。但是我们要分析其算法,所以这样是不行的。
所以我们网上看跳转
0040257 | 66:85F6 | test si,si |
0040257 | 8945 94 | mov dword ptr ss:[ebp-6C],eax |
0040257 | 894D AC | mov dword ptr ss:[ebp-54],ecx |
0040258 | 8945 A4 | mov dword ptr ss:[ebp-5C],eax |
0040258 | 894D BC | mov dword ptr ss:[ebp-44],ecx |
0040258 | 8945 B4 | mov dword ptr ss:[ebp-4C],eax |
0040258 | 74 58 | je afkayas.1.4025E5 |
发现有一个je 上面影响 zf标志位的只有test位置,test指令的意思 两个操作数按位与,这里就是判断si是否等于0
继续往上翻,看看si的值是怎么来的。
0040253 | FF15 2841400 | call dword ptr ds:[<&__vbaStrCmp>] |
0040253 | 8BF0 | mov esi,eax |
0040253 | 8D55 E0 | lea edx,dword ptr ss:[ebp-20] |
0040253 | F7DE | neg esi |
0040254 | 8D45 E8 | lea eax,dword ptr ss:[ebp-18] |
0040254 | 52 | push edx |
0040254 | 1BF6 | sbb esi,esi |
0040254 | 8D4D E4 | lea ecx,dword ptr ss:[ebp-1C] |
0040254 | 50 | push eax |
0040254 | 46 | inc esi |
才在这个call位置打个断点,因为我们不熟悉vb语言,所以我们采用多次调试的策略。来进行猜测其功能。cmp反正是与比较有关的。
堆栈的值
0019F040 004656EC L"AKA-1658111"
0019F048 08C92D64 L"Type In Your Serial"
其实这里就可以看出来了,如果相等就是0不相等就是1 或者 -1 盲猜一下
开始还原
发现是这样的。于是我们重新跑一下,看看正确的结果是什么。
用户名不变,直接改密码,我这里测试了一下, 我使用eax AKA-1658111 的时候,返回值为0
那我们再来个比这个字符串ASCII小的。
0019EF88 09D640A4 L"AKA-1658111"
0019EF8C 0045701C L"AAAAA"
发现eax为 FFFFFFFF
其实这里不管1或者-1最后都变成了0。等下我们要分析一下他的这一步的算法,先把这个还原看看。
到这里可以看出来。当用户名为:Type In Your Name
的时候。秘钥为"AKA-1658111"
以往的经验可以知道。- 的左右两边是分开的。所以……先看看AKA咋生成的。
0040251 | 68 701B400 | push afkayas.1.401B70 | 401B70:L"AKA-"
其实这里就可以看出来了,AKA- 是本来就在内存中的。也就是说不需要我们还原,就是写死的。
所以我们就要开始分析1658111 是如何生成的了。开始逆向还原了。首先我们可以猜到肯定是由用户名进行生成的。
翻到开始的位置
0040241 | 50 | push eax | eax:L"Type In Your Name"
0040241 | 8B1A | mov ebx,dword ptr ds:[edx] |
0040241 | FF15 E4404 | call dword ptr ds:[<&__vbaLenBstr>] |
0040241 | 8BF8 | mov edi,eax | 求字符串的长度
0040241 | 8B4D E8 | mov ecx,dword ptr ss:[ebp-18] | [ebp-18]:L"Type In Your Name"
0040242 | 69FF FB7C0 | imul edi,edi,17CFB |
发现有这个字符,
可以猜到。这个还原是
strlen("Type In Your Name") * 0x17CFB
下一步有一个jo。如果溢出则直接报错了就。无需管他。
继续向下分析
0040242 | 0F80 91020 | jo afkayas.1.4026BE |
0040242 | FF15 F8404 | call dword ptr ds:[<&rtcAnsiValueBstr>] |
0040243 | 0FBFD0 | movsx edx,ax | edx:L"ype In Your Name"
0040243 | 03FA | add edi,edx | edx:L"ype In Your Name"
这个函数也是使用多执行几次,猜测他的作用,这里是直接去取出第一个字符。
然后加上edi的结果。
0040243 | 0F80 80020 | jo afkayas.1.4026BE |
0040243 | 57 | push edi |
0040243 | FF15 E0404 | call dword ptr ds:[<&__vbaStrI4>] | 十六进制转十进制
0040244 | 8BD0 | mov edx,eax |
0040244 | 8D4D E0 | lea ecx,dword ptr ss:[ebp-20] |
最后这个呢。就是直接将16进制转换成十进制的字符串,这里转换完成后就已经拿到了结果了。
0040243 | FF15 E0404 | call dword ptr ds:[<&__vbaStrI4>] | 十六进制转十进制
0040244 | 8BD0 | mov edx,eax | edx:L"1658111", eax:L"1658111"
0040244 | 8D4D E0 | lea ecx,dword ptr ss:[ebp-20] |
也就是这样.后面的操作就没什么意义了已经,所以这里我们就拿到了正确的结果了。开始写代码。
#include<iostream>
#include<string>
const char* str = "AKA-";
int main()
{
std::string username;
std::getline(std::cin, username);
int nValue = username.length() * 0x17CFB + username[0];
std::string strRet = str + std::to_string(nValue);
std::cout << strRet << std::endl;
return 0;
}
输出结果测试
Type In Your Name
AKA-1658111
weiran
AKA-585305
没问题了
补课多分析一些。
首先我先把重点函数给提取出来
0040253 | F7DE | neg esi |
0040254 | 1BF6 | sbb esi,esi |
0040254 | 46 | inc esi |
0040254 | F7DE | neg esi |
好了好了就这四行
代码 | esi = 0 | esi = 1 | esi = -1 |
---|---|---|---|
neg esi | 0 cf = 0 | -1 cf = 1 | -1 cf = 0 |
sbb esi,esi | 0 | -1 | -1 |
inc esi | 1 | 0 | 0 |
neg esi | FFFFFFF | 0 | 0 |
所以这样就让所有的1或者-1都变成了 0 而0 变成了fffffff 这个就是结果了。所以当为0的时候跳转到一个其他打印,不为0时才跳转到正确的结果