[CrackMe]Chafe.1.exe的逆向及注册机编写

上手先试一下, 发现其没有对话框, 只有字符串, 搜索"Your serial is not valid"字符串

\

上来就直接发现关键跳转, 难道这题这么简单吗? 仔细一看实际上远远要复杂

往上一翻发现没有生成serial key的代码, 而是看到了一个SetTimer, 时间间隔设置成了1ms, 之前输入的时候发现有点卡顿, 就是因为定时器消息阻塞了消息队列。

既然这样, 那生成serial key的算法我估计就在这个定时器例程里, 由于SetTimer里面回调设置的是NULL, 所以要找到定时器例程肯定在WM_TIMER中, 要找到这个消息必须先找到窗口过程函数。定位到RegisterClassExA, 并找到对应的窗口过程函数。

设定条件断点, 实际上由于WM_TIMER时间很短, 不需要设定很容易就能捕获WM_TIMER消息, 但是这里还是使用这种方法

上来后就发现了一个call, serial key生成算法肯定在里面

这个crackme使用的思路是切换栈帧, 他自己构造了一个栈帧, 该构造的栈帧上有4个例程, 其通过挪动ESP指针来切换每个例程, 每次切换栈帧并调用对应例程如果成功都会有4的累计, 那最终会有4 * 4 = 0x10, 如果满足这个值那就说明serial key是正确的。

下面是第一次切换栈帧, 其目的是为了从serial编辑控件上获取值, 这个值会在第3次切换栈帧时被进行加密运算, 最终得到一个值。

如果你输入的serial key值长度不为0, 或者没有溢出。那么就代表例程执行成功, 这时会把JmpEspOffset += 4, 下次跳转到新栈帧时, 就会加上这个偏移使栈顶指针降低从而跳转到下一个新栈帧上的例程

接下来进入第2次, 由于第一次成功了, 即获得了符合条件的serial key, JmpEspOffset目前是4, 这个值代表了新构造的栈的偏移, 所以新栈顶要挪动4个字节

接着通过ret指令, 将栈顶例程地址pop到EIP里, 这样也就成功进入了下一个例程内

实际上这个crackme程序的name控件只会关注20个字节的内容, 这个例程的目的是为了把你输入的字符长度后面到最长20字节的内容全部清零, 如果你输入的name是有内容的。满足这个条件那JmpEspOffset不会发生变化。

马上要进入第3个例程了。第3个例程做的工作是遍历把你输入的name, 一共扫描16次, 每次获取name的4个字节。然后以你输入的serial key为基础进行如下加密:

cpp 复制代码
// 伪代码
int iPtr = 0;
while (iPtr < 16)
{
    SerialKey++;
    SerialKey ^= *(DWORD *)&name[iPtr] 
    iPtr++;
}

这种操作进行了16次后将JmpEspOffset在增加4, 此时, JmpEspOffset为0xC

接着将要进行最后一次例程执行, 其做的事很简单, 就是把第3次例程获取的值加上0x9112478, 如果说得出来的结果溢出并最终为0, 那就说明serial key正确。并将JmpEspOffset在增加4, 此时, JmpEspOffset为0x10

最终出来后, 首先JmpEspOffset会和上一次的JmpEspOffset值(SaveValTmp)进行对比, 如果不一样说明JmpEspOffset发生了变化(即例程执行成功, +4), 接着其会把最新的JmpEspOffset保存到SaveValTmp中后与0x10进行对比, 如果说一致那就说明serial key正确。

使用C++编写一个注册机, 如下:

根据第3个例程的算法进行反推获取如下核心代码:

(完)