此题对于各大牛来说就是送分项了,但是对于我这种新手还是有挑战的,特别是对数的浮点运算相关汇编指令比较陌生,关键还是能力太弱了,大牛看了我这篇分析处女作,对分析失误的地方还望不要见笑了,纯个人见解,可能是误打误撞对了,哈哈,好了,说了一堆废话,进入正题
工具:IDA
key:1555
算法:长度为4位,1,2位必须为1和5,3、4位为 (v1-0.2)*v11==24 v1为第3位,v11为第4位,成功截图:
开始分析:
运行WannaLOL.exe,在Key那随便输入一串数字,我输入的是135246点击Register按钮,提示“error!”
将程序扔到IDA,根据提示的失败信息“error!”,在IDA中搜索“error”,定位到.text:004012D6
.text:004012CF loc_4012CF: ; CODE XREF: sub_4011F4+35j
.text:004012CF ; sub_4011F4+41j ...
.text:004012CF push 0 ; uType
.text:004012D1 push offset Caption ; "CrackMe 2017 CTF v2"
.text:004012D6
.text:004012D6 loc_4012D6: ; CODE XREF: sub_4011F4+D2j
.text:004012D6 push offset Text ; "error !"
.text:004012DB
.text:004012DB loc_4012DB: ; CODE XREF: sub_4011F4+D9j
.text:004012DB push hWnd ; hWnd
.text:004012E1 call ds:MessageBoxA
.text:004012E7 leave
.text:004012E8 retn
.text:004012E8 sub_4011F4 endp
沿着“error!”信息向上看,发现了有个字符串"Registration successful !",这不就是成功的信息吗,接着向上看,根据IDA左侧红色虚线提示的跳转信息,应该就能确定这个是关键的算法就在此了
按F5,发现无法转换,选中.text:004011F4--.text:004012E8的这段代码,然后按P,再按F5就可以看到熟悉的C代码了,对key的算法已经可以看的很明白了,
大家直接看我在代码中的注释就可以了
int sub_4011F4()
{
int v0; // ecx@8
double v1; // st7@8
double v2; // st6@8
double v3; // st6@8
const CHAR *v5; // [sp-Ch] [bp-28h]@9
const CHAR *v6; // [sp-8h] [bp-24h]@8
CHAR String; // [sp+0h] [bp-1Ch]@1
char v8; // [sp+1h] [bp-1Bh]@3
char v9; // [sp+2h] [bp-1Ah]@4
char v10; // [sp+3h] [bp-19h]@5
int v11; // [sp+18h] [bp-4h]@8
// 获取输入的key
GetDlgItemTextA(hDlg, 1001, &String, 21);
// 延时500毫秒
Sleep(0x1F4u);
// 这里是第一处的判断
/**
* 如果其中只要有一个条件成立,就会跳到失败信息弹出框
* 1.strlen(&String) != 4 判断输入key的长度,长度不为4就跳转到失败信息弹出框
* 2.String == 48 || v8 == 48 || v9 == 48 || v10 == 48 --> 分别为输入的第1,2,3,4位字符的值,48就是ASCII的0,就是输入的key中不能有0
* 3.String != 49 || v8 != 53 --> 分别为输入的第1,2位的字符的值必须为1和5,这里就能确定1,2位了
*/
if ( strlen(&String) != 4 || String == 48 || v8 == 48 || v9 == 48 || v10 == 48 || String != 49 || v8 != 53 )
{
// Caption值为'CrackMe 2017 CTF v2'
v6 = Caption;
goto LABEL_11;
}
// 下面这三行代码不知道是干什么用的,花指令?对代码好像没什么影响,还望大牛能指导
JUMPOUT(v8 == 53, (char *)&loc_401262 + 1);
JUMPOUT(0, (char *)&loc_401262 + 1);
v48CACD();
// 下面是将1到4位的值转换为double,对应key的位置为:
// 1 2 3 4
// v2 v3 v1 v11
v11 = v9 - v0;
v1 = (double)v11;
v11 = String - v0;
v2 = (double)v11;
v11 = v8 - v0;
// v3 = v2/v3 因为1,2位的值为1和5,所以就是1/5,因为是double运算,所以结果值为0.2
v3 = v2 / (double)v11;
v11 = v10 - v0;
// 到这里算法已经很清晰了,3,4位的值就是根据这个算式算出来的,结合下面的错误信息弹出框可以得到结论这个算式的值必须为384.0
// 这里再把算式简化下(v1-0.2)*v11*16.0=384 --> (v1-0.2)*v11==24
// 既然算式都出来了,就写个js脚本穷举下就可以得出3,4位的值为55了,js脚本在下面,到此整个算法逆向分析结束
*(float *)&v11 = (v1 - v3) * (double)v11 * 16.0;
// 下面这三行代码不知道是干什么用的,花指令?对代码好像没什么影响,还望大牛能指导
JUMPOUT(v10, v0, (char *)&loc_4012AA + 1);
JUMPOUT(v10 != v0, (char *)&loc_4012AA + 1);
v48CB15();
// aCrackme2017Ctf值为'CrackMe 2017 CTF'
v6 = aCrackme2017Ctf;
if ( *(float *)&v11 != 384.0 )
{
// 错误信息弹出框
LABEL_11:
// Text值为'error !'
v5 = Text;
return MessageBoxA(hWnd, v5, v6, 0);
}
// aRegistrationSu值为'Registration successful !'
v5 = aRegistrationSu;
return MessageBoxA(hWnd, v5, v6, 0);
}
js脚本
<html>
<head>
<script type="text/javascript">
function a(){
for (var i = 1; i < 10; i++) {
for (var j = 1; j < 10; j++) {
if((i-0.2)*j==24){
alert("x="+i+",y="+j+"\n");
}
}
};
}
a();
</script>
</head>
<body>
</body>
</html>
以上为全部的分析,不知分析的对不对,有不对的地方还望指出,感谢!
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课