骑着驴子追宝马 发表于 2021-11-13 16:53

网鼎杯2020青龙组jocker

一.程序分析首先还是将程序进行查壳
https://img-blog.csdnimg.cn/c9fea76a5e4b4ba0a84229ab7046c49d.png

IDA打开后尝试f5,发现因为堆栈不平衡,无法直接反编译,所以修改一下
https://img-blog.csdnimg.cn/f6c71fca9a594cc9a13a22d2283e0234.png

勾选堆栈指针,快捷键alt+k,将SP修改为零,如果下面还遇到同理
https://img-blog.csdnimg.cn/dc5d749348bb490ea7623b0c77c90656.png

二.伪代码分析 int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; //
char v5; //
DWORD flOldProtect; //
size_t v7; //
int i; //

__main();
puts("please input you flag:");
if ( VirtualProtect(encrypt, 0xC8u, 4u, &flOldProtect) == 0 )
    exit(1);
scanf("%40s", &v4);
v7 = strlen(&v4);
if ( v7 != 24 )
{
    puts("Wrong!");
    exit(0);
}
strcpy(&v5, &v4);
wrong(&v4);
omg(&v4);
for ( i = 0; i <= 186; ++i )
    *((_BYTE *)encrypt + i) ^= 0x41u;
if ( encrypt(&v5) != 0 )
    finally(&v5);
return 0;
}

查看伪代码,直接可以看出flag字符串长度是0x18也就是24,有两个加密函数,wrong和omgwrong:首先对输入的flag的每个字节根据并1后是否为真进行了亦或下标的操作char *__cdecl wrong(char *a1)
{
char *result; // eax
signed int i; //

for ( i = 0; i <= 23; ++i )
{
    if ( i & 1 )
    {
      result = &a1;
      a1 -= i;
    }
    else
    {
      result = &a1;
      a1 ^= i;
    }
}
return result;
}

omg:wrong得到的结果跟一个全局变量unk_4030C0比较int __cdecl omg(char *a1)
{
int result; // eax
int v2; //
int i; //
int v4; //

v4 = 1;
qmemcpy(v2, &unk_4030C0, sizeof(v2));
for ( i = 0; i <= 23; ++i )
{
    if ( a1 != v2 )
      v4 = 0;
}
if ( v4 == 1 )
    result = puts("hahahaha_do_you_find_me?");
else
    result = puts("wrong ~~ But seems a little program");
return result;
}

可以简单还原出来,但发现是一个假的flag
https://img-blog.csdnimg.cn/c5293786cc654538af382f76e769ad58.png

脚本:
result="fkcd\x7fagd;Vka{&;Pc_MZq\x0c7f"i=0
flag=""
for j in result:
    if(i&1):
      flag+=chr(ord(j)+i)
    else:
      flag+=chr(ord(j)^i)
    i+=1
print flag

三.smc自修改代码在下面分析时,发现一个encrpt函数,但f5并不能反汇编成功
https://img-blog.csdnimg.cn/e52da967419e4104901b6720754347cc.png

for ( i = 0; i <= 186; ++i )
    *((_BYTE *)encrypt + i) ^= 0x41u;
if ( encrypt(&v5) != 0 )
    finally(&v5);

这里的for循环应该是把程序里加壳的部分给脱壳,所以动态调试,也因为看到这么多次的循环,猜测为smc自修改代码 意思是自我修改的代码,使程序在运行时自我修改。
$$
用途包括:1) 使一些重要的跳转位置爆破无效化 (以 smc 对重要位置进行覆写)2) 使一些重要代码隐藏 (在必要时才实时产生重要代码段,防止程序被人静态分析,也防止一些透过搜寻的破解方法)
$$
在汇编视图的界面,可以看到对一个函数进行了一些操作,很明显可以看出右边的操作是循环对这个函数进行解密,解密之后直接调用,进去这个函数会发现是一堆乱码。
https://img-blog.csdnimg.cn/2fddd073f4fe46d38f1ed5dd9b253afd.png

https://img-blog.csdnimg.cn/397b5086567448bb9fe1e4d71ef0ae9f.png

所以OD直接定位到这个函数,下断点,
https://img-blog.csdnimg.cn/faa63df846a94501bf939d2d446dbfa1.png

这一部分对应的是刚才的for循环
https://img-blog.csdnimg.cn/20200515160448684.png

f7进入call,会发现这里已经解密
https://img-blog.csdnimg.cn/9f52238ba07f474882aa46607fe0f24f.png

用olldump直接脱壳
https://img-blog.csdnimg.cn/95a2eaf99aeb42948017ffe96152067c.png

这时候就可以用IDA的f5静态调试了int __cdecl sub_401500(int a1)
{
int v2; //
int v3; //
int i; //

v3 = 1;
qmemcpy(v2, &unk_403040, sizeof(v2));
for ( i = 0; i <= 18; ++i )
{
    if ( (char)(*(_BYTE *)(i + a1) ^ aHahahahaDoYouF) != v2 )
    {
      puts("wrong ~");
      v3 = 0;
      exit(0);
    }
}
if ( v3 == 1 )
    puts("come here");
return v3;
}

对输入的内容和hahahaha_do_you_find_me?这个字符串进行异或,然后和一个全局变量进行比较,注意只异或了19个字节,然后写出脚本还原一下:
result2="\x0e\x0d\x09\x06\x13\x05\x58\x56\x3e\x06\x0c\x3c\x1f\x57\x14\x6b\x57\x59\x0d"
flag=""
haha="hahahaha_do_you_find_me?"
for i in range(19):
    flag+=chr(ord(haha)^ord(result2))
print(flag)
​flag{d07abccf8a410c

只有十九个字节,还缺少五个,IDA中看程序的逻辑发现调用flag校验函数之后还有一个finally函数,这个函数正常执行是执行不到的,这个函数同样是加密的,从刚刚从OD中脱出来的程序中可以看到这个函数的明文:int __cdecl sub_40159A(_BYTE *a1)
{
unsigned int v1; // eax
int result; // eax
char v3; //
char v4; //
char v5; //
char v6; //
char v7; //
int v8; //
int v9; //

v3 = '%';
v4 = 't';
v5 = 'p';
v6 = '&';
v7 = ':';
v1 = time(0);
srand(v1);
v9 = rand() % 100;
v8 = 0;
if ( (*a1 != '%') == v9 )
    result = puts("Really??? Did you find it?OMG!!!");
else
    result = puts("I hide the last part, you will not succeed!!!");
return result;
}

这里每次得数都是随机的,根本无法爆破,因为flag最后一个字节一定是‘}’,那么用‘:’^‘}’=0x47,然后使用“%tp&:”分别异或0x47得到最后5个字节。 完整的脚本:
result2="\x0e\x0d\x09\x06\x13\x05\x58\x56\x3e\x06\x0c\x3c\x1f\x57\x14\x6b\x57\x59\x0d\x47\x47\x47\x47\x47"
flag=""
haha="hahahaha_do_you_fin%tp&:"
for i in range(24):
    flag+=chr(ord(haha)^ord(result2))
print(flag)flag{d07abccf8a410cb37a}

qiweiview 发表于 2021-11-18 22:19

酷,学习了

yyspawn 发表于 2021-11-19 09:40

thams 发表于 2021-11-22 15:51

谢谢楼主,学习了

binghe01 发表于 2024-10-19 10:42

谢谢楼主学习到了
页: [1]
查看完整版本: 网鼎杯2020青龙组jocker