160CM-034
1. 爆破
程序打开以后,没有注册按钮和窗口,只有一个uncracked的提示。直接拖进OD中,从头往下看,可以很容易的看出程序流程:
① 判断CRACKME3.key文件是否存在;
② 读取文件内容并判断读取内容的字节数;
③ 将读取到的内容按两个校验算法进行计算,比较结果是否相同。
因此,要爆破就需要将上述三处判断的跳转都改到正确的流程上去,需要:
(1)401035处,将jnz short 00401043
改为jmp short 00401043
;
(2)40106D处,将jnz short 00401037
改为nop
;
(3)40109F处,将je short 00401037
改为nop
;
上述修改完成后,程序启动后的菜单栏提示已经变成了Cracked的字样,但是没有破解成功的提示框弹窗,还需要在40118A处,将jnz short 004011A3
改为nop
,这样就全部爆破就完成了。
2. 算法分析
先分析校验算法1,用IDA打开程序,找到算法子程序401311
,按F5得到伪代码,如下图:
从伪代码中可以看出,算法依次将每个字节与变量v4(从65到79每次加1)进行异或计算,然后将结果累加,共执行14次。
然后累加结果再与0x12345678
进行异或计算。
校验算法2很简单,将从文件中读取到的内容,取第15~18字节的内容,当成整型变量值。
然后比较算法1的异或结果和算法2得到的整型变量是否相等,相等则成功。
另外,由于注册成功后提示的字符串是异或后的结果,如果要显示希望的字符,则需要先进行异或处理后,将异或处理后的内容当做1~14字节的内容。
编写注册机算法程序如下:
// 160CrackMe-034.cpp : 定义控制台应用程序的入口点。#include "stdafx.h"#include <Windows.h>#include <stdio.h>#include <math.h>int _tmain(int argc, _TCHAR* argv[]){ char input[50],String1[18]; int i, j,length; int k,temp; int code1; printf("请输入用户名:"); scanf_s("%s", input, 50); length = strlen(input); k = 65; //现将用户名异或处理得到长度为14字节的字符串 for (i = 0; i < 14; i++) { if (i<length) { String1[i] = input[i] ^ k; } else { String1[i] = 0 ^ k; } k++; } j = 0; k = 65; code1 = 0; do { temp = k ^ String1[j]; k++; code1 = code1+temp; if (!temp) break; j++; } while (k != 79); code1 = code1 ^ 0x12345678; String1[14] = code1 & 0xFF; String1[15] = (code1 & 0xFF00)8; String1[16] = (code1 & 0xFF0000) 16; String1[17] = (code1 & 0xFF000000) 24; char * path = "z:\\CRACKME3.KEY"; FILE * pfile; fopen_s(&pfile, path, "w"); fwrite(String1, sizeof(byte), 18, pfile); fclose(pfile); system("pause"); return 0;}
输入用户名helloworld
,生成key文件后,将文件复制到程序目录下,运行程序,验证成功。
3. 总结
这道题由于异或计算会得到非可见的ASCII码字符,因此注册机输出文本信息会有不可见的字符,需要直接二进制写入key文件。