zbnysjwsnd8 发表于 2019-7-5 10:55

重新发一个CrackMe

之前那个写法上有点小问题
现在重发一下。

梦游枪手 发表于 2019-7-5 21:32

本帖最后由 梦游枪手 于 2019-7-11 13:44 编辑

程序直接丢IDA分析,定位到sub_4010D3,IDA对易语言程序不太友好,伪代码不全,可以的话阅读汇编更容易理解
int sub_4010D3()
{
signed __int64 v0; // rax
double v1; // st7
void *v2; // eax
void *v3; // eax
void *v4; // eax
void *v5; // eax
unsigned __int8 *v7; //
void *v8; //
void *v9; //
void *v10; //
void *v11; //
void *v12; //
void *v13; //
void *v14; //
void *v15; //
void *v16; //
void *v17; //
void *v18; //
void *v19; //
void *v20; //
void *v21; //
void *v22; //
double v23; //
LPVOID v24; //
LPVOID v25; //
LPVOID v26; //
signed int v27; //

v26 = 0;
v25 = 0;
v24 = (LPVOID)sub_4023FB(4u);
*(_DWORD *)v24 = 0;
v23 = 0.0;
call((void (__cdecl *)(__int64 *))gettickcount);
call((void (__cdecl *)(__int64 *))sub_403350);
call((void (__cdecl *)(__int64 *))sub_402710);
v27 = call((void (__cdecl *)(__int64 *))rand);// 取随机数
v19 = (void *)call((void (__cdecl *)(__int64 *))getcurrentdir);
v15 = (void *)strappend((char)v19);
if ( v19 )
    free(v19);
v11 = (void *)call((void (__cdecl *)(__int64 *))readfile);// 读取当前目录下的key.txt
if ( v15 )
    free(v15);
v9 = (void *)call((void (__cdecl *)(__int64 *))tostr);
if ( v11 )
    free(v11);
if ( v26 )
    free(v26);
v26 = v9;
v16 = (void *)b64_decode(&v26, 0, 0);         // base64解码
v12 = (void *)call((void (__cdecl *)(__int64 *))tostr);
if ( v16 )
    free(v16);
if ( v25 )
    free(v25);
v25 = v12;
v20 = (void *)call((void (__cdecl *)(__int64 *))tostr);
stack(1, 0, 0x80000002);
v17 = (void *)call((void (__cdecl *)(__int64 *))replacesubtext);// 用前面生成的rand替换掉key.txt的'x'
if ( v20 )
    free(v20);
v21 = v17;
if ( v25 )
    free(v25);
v25 = v21;
call2((void (__cdecl *)(__int64 *, int, char *))calc, 6);// 计算替换后的表达式的值
LODWORD(v0) = getresult(v27);               // 用rand取真实结果
v1 = v23 - (double)v0;                        // 表达式的值与真实值相减,为0则成功
if ( v1 < 0.0 )
    v1 = -v1;
if ( v1 <= 0.0000001 )
{
    call((void (__cdecl *)(__int64 *))tochararr);// 表达式转字节集
    call2((void (__cdecl *)(__int64 *, int, char *))getmd5, 1);// 取MD5
    free((LPVOID)0x80000005);
    v2 = (void *)call2((void (__cdecl *)(__int64 *, int, char *))desdecrypt, 3);// 解密信息框的内容,密钥是上面取得的MD5
    if ( !v2 )
      v2 = &unk_49BC1E;
    v13 = v2;
    call((void (__cdecl *)(__int64 *))tostr);
    if ( v13 )
      free(v13);
    stack(LODWORD(v23), HIDWORD(v23), v24);
    call((void (__cdecl *)(__int64 *))messagebox);
    free((LPVOID)0x80000004);
    v27 = -2147483644;
    v26 = 0;
    v25 = &unk_49BC1D;
    v24 = (LPVOID)1;
    v3 = (void *)call((void (__cdecl *)(__int64 *))tochararr);
    v22 = v3;
    v27 = -2147483643;
    v26 = 0;
    if ( !v3 )
      v3 = &unk_49BC1E;
    v25 = v3;
    v18 = (void *)call2((void (__cdecl *)(__int64 *, int, char *))getmd5, 1);
    if ( v22 )
      free(v22);
    v27 = -2147482879;
    v26 = 0;
    v25 = (LPVOID)2;
    v24 = (LPVOID)-2147483644;
    HIDWORD(v23) = 0;
    v4 = v18;
    if ( !v18 )
      v4 = &unk_49BC1D;
    LODWORD(v23) = v4;
    v14 = (void *)call2((void (__cdecl *)(__int64 *, int, char *))desdecrypt, 3);
    v27 = -2147483643;
    v26 = 0;
    v5 = v14;
    if ( !v14 )
      v5 = &unk_49BC1E;
    v25 = v5;
    v24 = (LPVOID)1;
    v10 = (void *)call((void (__cdecl *)(__int64 *))tostr);
    if ( v14 )
      free(v14);
    v8 = (void *)sub_402413(1375797249, 100728832, 8, -1);
    v27 = (signed int)v10;
    v26 = &unk_49BC49;
    v7 = (unsigned __int8 *)strappend((char)v8);
    if ( v8 )
      free(v8);
    if ( v10 )
      free(v10);
    sub_40240D((HWND)0x52010001, 100728832, 8, -1, v7, 0);
    if ( v7 )
      free(v7);
}
if ( v26 )
    free(v26);
if ( v25 )
    free(v25);
return free(v24);
}
表达式计算出来的结果跟getresult函数的返回值要一致,看看getresult的代码
int __stdcall getresult(__int64 a1)
{
bool v1; // zf
__int64 v3; // rax
signed __int64 v4; // rax

v1 = (_DWORD)a1 == 1;
if ( (_DWORD)a1 == 1 )
    v1 = HIDWORD(a1) == 0;
if ( v1 )
    return 6;
LODWORD(v3) = toint((double)a1 - 1.0);
LODWORD(v4) = getresult(v3);
return toint(
         (((double)a1 + 1.0) * (double)v4 + ((double)a1 - 1.0) * (double)a1 * ((double)a1 + 1.0) * 2.0)
         / ((double)a1 - 1.0));
}
代码比较简单,自己写一下这个函数
def dfs(x):
    if x==1:
      print 'x=%d,result=6' % x
      return 6
    r=dfs(x-1)
    ret=((x+1)*r+(x-1)*x*(x+1)*2)/(x-1)
    print 'x=%d,result=%d' % (x,ret)
    return ret
if __name__=='__main__':
    dfs(10)

运行后输出:
x=1,result=6
x=2,result=30
x=3,result=84
x=4,result=180
x=5,result=330
x=6,result=546
x=7,result=840
x=8,result=1224
x=9,result=1710
x=10,result=2310
设dfs函数为f(x),则有
f(1)=6=6*1
f(2)=30=6*5=6*(2^2+1)
f(3)=84=6*14=6*(3^2+2^2+1)
...
如果有接触过平方和公式的话很容易就能从这些结果看出来了,不巧的是我花了不少时间。
平方和公式:n*(n+1)*(2n+1)/6
所以f(x)=x*(x+1)*(2*x+1)
将这条式子base64编码后得到:
eCooeCsxKSooMip4KzEp
把字符串写到key.txt就行了。

dajiyuan22 发表于 2019-7-5 13:15

感谢分享

Smallhorse 发表于 2019-7-5 13:40

本帖最后由 Smallhorse 于 2019-7-5 14:40 编辑


这是为什么?

Rokki 发表于 2019-7-5 13:51

新手表示,这个真的是好东西,哈哈

WHDYAIGYHY 发表于 2019-7-5 13:51

厉害厉害厉害

tardis 发表于 2019-7-5 14:24

感谢分享

梦游枪手 发表于 2019-7-5 14:54

搞定了,不过我对这个公式没啥印象,不知道是我忘记了,还是以前上课的时候就没讲过。。。

axldh 发表于 2019-7-5 15:40

新手表示,这个真的是好东西,哈哈

liaolaotou 发表于 2019-7-5 15:58

怎么使用呢?
页: [1] 2
查看完整版本: 重新发一个CrackMe