本帖最后由 sighout 于 2016-9-9 17:19 编辑
先说说上篇文章最后留的作业 这是我做的,可能不是最好的方法 这个简单,把代码中和0xA比较改为和0x1比较就OK了。 第二个也不是很难,初始化显示成功 在初始化数据“DEAD”“42424242”和错误信息后的跳转,直接跳到Call正确信息的地方。
注意: 1、 需要把3次错误检查的地方Nop掉,否则点三次按钮还是会出现暴力破解信息。 2、 点第二次的时候会回到一个错误发生字串,这里我还没想到要怎么处理,有思路的请提供想法,谢谢!(其实用奇偶的方法可以做,但是代码空间可能够)
以上就是作业的思路,有兴趣的再去试试看,可能你的方法比我好。欢迎提供不同的思路。
【翻译】R4ndom破解教程全文翻译(For新手):第十六章(下)
翻译都是我理解的方式进行描述,可能和原文不一致。
正文开始了
暴力破解是一种方法,这中方法是你可以从程序中找到爆破点然后直达我们需要的地方,虽然通过常规的加密/解密你已经知道这个程序的输入和输出,但是你不知道他的解密过程,而是直接打了一个补丁就完事。而这种方法与通过输入用户名和序列号的方式是不同的。如果你以前下载过破解软件,是通过输入用户名和序列号来让程序工作的,它有可能是通过暴力破解来的。
这种工作方式是通过常规的加密/解密输入的用户名和序列号,你尝试不同的输入直到有一次匹配成功,例如:我们输入“12121212”,程序通过常规解密后得到“j6^^gD7-L”,我们使用不同的输入,得到的结果是不同的。我们就是要想办法知道“12121212”是怎么变成“j6^^gD7-L”的,然后让我们的输入的序列号能让程序启动,或者能够注册成功。
请记住,这中方法只适用于程序内部检查用户名和序列号,不适用于网络验证。
和大家说的一样,暴力破解不是难事,首先你至少知道一门编程语言这样就可以自己编写暴力破解的程序,此教程主要是汇编语言,因为要分析代码中的算法。作者自己也会两门其他编程语言____,因此你就可以在高级语言中做暴力破解算法(译者注:我只会C++初阶)
另一个就是要明白用户名和序列号是怎么变成输出的,这样做的原因是它减少了操作次数,所以我们必须尝试。如果我说我们必须在密码栏输入“SECRET“导致输出为”MESSAGE”。这有无限多的方法。但是如果我说把用户名做异或操作后的值很有价值,这样会减少很多方法。
破译密码
还记得前面的教程中我问你是否能破译密码吗,修改什么地方能出现成功,下面就是所有的程序代码: (译者注:这里后面的解释好像ecx和eax反了,我自己是吧eax当作a,ebx当作b,ecx当作c,然后我放上我的解释) 004012A9 mov ecx, dword_403040 ; 变量 'c' 004012AF mov ebx, dword_40303C ; 变量 'b' 004012B5 mov eax, dword_403038 ; 变量 'a' 004012BA cmp [ebp+arg_0], 1 ; ***** Button 1 004012BE jnz short loc_4012D0 004012C0 add ecx, 54Bh ;c += 54Bh 004012C6 imul ebx, eax ; b *= a 004012C9 xor eax, ecx ; a^= c 004012CB jmp loc_4013E7 004012D0 cmp [ebp+arg_0], 2 ; ***** Button 2 004012D4 jnz short loc_4012E8 004012D6 sub ecx, 233h ; c -= 233h 004012DC imul ebx, 14h ; b *= 14h 004012DF add ecx, eax ; c += a 004012E1 and ebx, eax ; b &= a 004012E3 jmp loc_4013E7 004012E8 cmp [ebp+arg_0], 3 ; ***** Button 3 004012EC jnz short loc_4012FD 004012EE add eax, 582h ; a += 582h 004012F3 imul ecx, 16h ; c *= 16h 004012F6 xor ebx, eax ; b ^= a 004012F8 jmp loc_4013E7 004012FD cmp [ebp+arg_0], 4 ; ***** Button 4 00401301 jnz short loc_401312 00401303 and eax, ebx ; a &= b 00401305 sub ebx, 111222h ; b -= 111222h 0040130B xor ecx, eax ; c ^= a 0040130D jmp loc_4013E7 00401312 cmp [ebp+arg_0], 5 ; ***** Button 5 00401316 jnz short loc_401324 00401318 cdq 00401319 idiv ecx ; a /= c, divisionrest --> (r) 0040131B sub ebx, edx ; b -= r 0040131D add eax, ecx ; a += c 0040131F jmp loc_4013E7 00401324 cmp [ebp+arg_0], 6 ; ***** Button 6 00401328 jnz short loc_401339 0040132A xor eax, ecx ; a ^= c 0040132C and ebx, eax ; b &= a 0040132E add ecx, 546879h ; c += 546879h 00401334 jmp loc_4013E7 00401339 cmp [ebp+arg_0], 7 ; ***** Button 7 0040133D jnz short loc_401351 0040133F sub ecx, 25FF5h ; c -= 25FF5h 00401345 xor ebx, ecx ; b ^= c 00401347 add eax, 401000h ; a += 401000h 0040134C jmp loc_4013E7 00401351 cmp [ebp+arg_0], 8 ; ***** Button 8 00401355 jnz short loc_401367 00401357 xor eax, ecx ; a ^= c 00401359 imul ebx, 14h ; b *= 14h 0040135C add ecx, 12589h ; c += 12589h 00401362 jmp loc_4013E7 00401367 cmp [ebp+arg_0], 9 ; ***** Button 9 0040136B jnz short loc_401378 0040136D sub eax, 542187h ; a -= 542187h 00401372 sub ebx, eax ; b -= a 00401374 xor ecx, eax ; c ^= a 00401376 jmp short loc_4013E7 00401378 cmp [ebp+arg_0], 0Ah ; ***** Button 10 0040137C jnz short loc_40138A 0040137E cdq 0040137F idiv ebx ; a /= b, division rest -->(r) 00401381 add ebx, edx ; b += r 00401383 imul eax, edx ; a *= r 00401386 xor ecx, edx ; c ^= r 00401388 jmp short loc_4013E7 0040138A cmp [ebp+arg_0], 0Bh ; ***** Button 11 0040138E jnz short loc_4013A3 00401390 add ebx, 1234FEh ; b += 1234FEh 00401396 add ecx, 2345DEh ; c += 2345DEh 0040139C add eax, 9CA4439Bh ; a += 9CA4439Bh 004013A1 jmp short loc_4013E7 004013A3 cmp [ebp+arg_0], 0Ch ; ***** Button 12 004013A7 jnz short loc_4013B2 004013A9 xor eax, ebx ; a ^= b 004013AB sub ebx, ecx ; b -= c 004013AD imul ecx, 12h ; c *= 12h 004013B0 jmp short loc_4013E7 004013B2 cmp [ebp+arg_0], 0Dh ; ***** Button 13 004013B6 jnz short loc_4013C8 004013B8 and eax, 12345678h ; a &= 12345678h 004013BD sub ecx, 65875h ; c -= 65875h 004013C3 imul ebx, ecx ; b *= c 004013C6 jmp short loc_4013E7 004013C8 cmp [ebp+arg_0], 0Eh ; ***** Button 14 004013CC jnz short loc_4013DB 004013CE xor eax, 55555h ; a ^= 55555h 004013D3 sub ebx, 587351h ; b -= 587351h 004013D9 jmp short loc_4013E7 004013DB cmp [ebp+arg_0], 0Fh ; ***** Button 15 004013DF jnz short loc_4013E7 004013E1 add eax, ebx ; a += b 004013E3 add ebx, ecx ; b += c 004013E5 add ecx, eax ; c += a *** 特别感谢figugegl 在他的教程中为我做了大部分工作 (当我发现我已经完成了三分之二后). ***
现在我们知道了每一个按钮都做了什么操作了。接下来我们需要的是输入和输出。这是我们已经知道的数据了,在代码自修改段中有官方(译者注:程序自己的算法,我们分析的代码)的算法,然后进行一些列合法的异或操作。具体就是与变量a、b、c进行异或后保存,然后第二个以后的数据都是和之前异或后的数据进行再次异或。
地址 401407的值EB 3F 90 90 与a 异或后为 528B550C(这个值是我们之前修改出来的)然后反向求出 a为 B9B4C59C 地址 40143B的值04 66 E7 BB与b 异或后为FF 75 0C 6A 然后可反向求出b 就是直接与结果异或就OK了 地址 40143F 的值 4D BD 08 8B与c 异或后为03 FF 75 08 然后可反向求出c
我们最终要做的是尝试修改的每一个组合,通过点击按钮模仿每一个尝试手动可能的组合,当我们做了10次按钮操作后,我们可以看到a\b\c中的值,这个就是正确的值。(译者注:不明白为什么是正确的值,是我们补丁后的程序?)
这个程序的作者提供了前两个值是7和9.给出的原因是,如果你的电脑比较慢的话,要把所有有可能的值都试一次的话要花费太多时间,在不知道前两位的情况下我用一台8核的电脑花了大约1小时才破译出密码。知道前两位的情况下只花了大约1分钟。通常在破解程序时我们不会有任何的提示(当然),我在破译程序中有包含两个已知的数。
下面是C语言写的破译程序 #include <iostream> using namespace std;
void brute( void ) { char finalAsciiSerial[11] = ""; int i, varA, varB, varC,tempVar, tempSerial[10];
// we know the first number is '7' for (tempSerial[0] = 7;tempSerial[0] <= 7; tempSerial[0]++) { // and we know the second number is '9' for (tempSerial[1] = 9;tempSerial[1] <= 9; tempSerial[1]++) { for (tempSerial[2] = 1;tempSerial[2] <= 15; tempSerial[2]++) { for (tempSerial[3] = 1;tempSerial[3] <= 15; tempSerial[3]++) { for (tempSerial[4] = 1;tempSerial[4] <= 15; tempSerial[4]++) { cout << "."; // Update display for (tempSerial[5] = 1;tempSerial[5] <= 15; tempSerial[5]++) { for (tempSerial[6] = 1;tempSerial[6] <= 15; tempSerial[6]++) { for (tempSerial[7] = 1;tempSerial[7] <= 15; tempSerial[7]++) { for (tempSerial[8] = 1;tempSerial[8] <= 15; tempSerial[8]++) { for (tempSerial[9] = 1;tempSerial[9] <= 15; tempSerial[9]++) { // Reset variables varA = 0xDEAD; varB = 0xDEAD; varC = 0x42424242;
// Apply each digit for (i = 0; i < 10; i++) { switch (tempSerial) { case 1: varC += 0x54B; varB *= varA; varA ^= varC; break ;
case 2: varC = varC - 0x233 +varA; varB = (varB * 0x14)& varA; break ;
case 3: varA += 0x582; varC *= 0x16; varB ^= varA; break ;
case 4: varA &= varB; varB -= 0x111222; varC ^= varA; break ;
case 5: if (varC != 0) // Watch divide by zero! { varB -= (varA %varC); varA /= varC; varA += varC; } break ;
case 6: varA ^= varC; varB &= varA; varC += 0x546879; break ;
case 7: varC -= 0x25FF5; varB ^= varC; varA += 0x401000; break ;
case 8: varA ^= varC; varB *= 0x14; varC += 0x12589; break ;
case 9: varA -= 0x542187; varB -= varA; varC ^= varA; break ;
case 10: if (varB != 0) // Watch divide by zero! { tempVar = varA %varB; varA /= varB; varB += tempVar; varA *= tempVar; varC ^= tempVar; } break ;
case 11: varB += 0x1234FE; varC += 0x2345DE; varA += 0x9CA4439B; break ;
case 12: varA ^= varB; varB -= varC; varC *= 0x12; break ;
case 13: varA &=0x12345678; varC -= 0x65875; varB *= varC; break ;
case 14: varA ^= 0x55555; varB -= 0x587351; break ;
case 15: varA += varB; varB += varC; varC += varA; break ; } }
// stop if serial equals propervalues if ((varA == 0x9CC5B4B9) &&(varB == 0xD1EB13FB) &&(varC == 0x837D424E)) { // Convert to ASCII for (i = 0; i < 10; i++) { if (tempSerial <= 9) { finalAsciiSerial= tempSerial + 0x30; } else { finalAsciiSerial = tempSerial +0x37; } } cout << "\n\n***** Bruteforced serial: "; cout<< finalAsciiSerial << "\n"; return; }}}}}}}}}}} }
int main() { cout << "Bruteforcerby R4ndom\n\n";
brute();
cout << "\nBruteforcing done...\n";
return 0; }
首先,建立我们的变量a\b\c,然后我们知道第一个和第二个是7和9,后面的是在1-15之间,然后我插入了一个“点”字串在控制台中输出,我不太喜欢程序没有任何反应,能看到解密的动作,证明程序没有当掉。
接下来,我们执行的变量的修改取决于哪个键被按下,就像我们在上面显示的一样。 当输入10个数据时(因为长度是10位),我们会检查这三个变量,看它们是否与我们程序中比较的数据一致,如果一致,我们则停下来,把这个数据转换为ASCII码,然后把它显示在程序上。如果不一致则继续进行下一条数据。 下面是控制台破译过程和结果: 让我输入破译后的密码看看程序怎么运行
我们现在已经破译了这个程序。
译者注:算法中要注意5和7里面,5和A是一样的东西
由于工作关系,后面的文章可能会比较晚才进行翻译,因为我要正在破解了,才能写出我理解的流程,才能在这里告诉大家。
文章链接和程序放到附件中
|