这道题目运行,输入11111111111 回车,程序直接关闭,没有任何提示信息
Exeinfo PE查壳发现是一个C++程序并且没有加壳
IDA x32载入程序 shift + F12查看有没有什么可以字符串
发现一个’Please input:’
双击进去 接着双击引用
程序流程图貌似很简单的样子
F5查看伪代码
进行简单分析 Src是一个字符串数组 unsigned int是错误的
我们双击Src看下在程序中的位置
发现是在.data段也就是数据段(data segment),通常是指用来存放程序中已初始化的全局变量的一块内存区域,那Src是一个32位的全局字符串数组变量 双击sub_411302()进去 发现最后返回的是中间的参数 也就是result
双击sub_411352() 进行分析
接着双击sub_413910()
int __usercall sub_413910@<eax>(int a1@<xmm0>, char *Str)
{
char v2; // cl
size_t i; // [esp+D0h] [ebp-8h]
sub_4112F8((int)&unk_421008);
for ( i = 0; i < j_strlen(Str); ++i ) // 将Str这个字符串分为三组 分别与0x1f,0x20,0x21进行异或
{
if ( i % 3 )
{
if ( i % 3 == 1 )
v2 = Str[i] ^ 0x20;
else
v2 = Str[i] ^ 0x21;
Str[i] = v2;
}
else
{
Str[i] ^= 0x1Fu;
}
}
return sub_411302(1, (int)Str, a1); // 最后返回a1
}
总的分析
int __usercall sub_413E30@<eax>(int a1@<xmm0>)
{
int v1; // eax
int v3; // [esp+0h] [ebp-CCh]
sub_4112F8((int)&unk_421008);
sub_411276(std::cout, "Please input: "); // cout输出提示信息
scanf((const char *)&my_input, (unsigned int)Src, 32);// scanf输入 保存在Src
if ( j_strlen(Src) >= 14 && j_strlen(Src) <= 32 )// 判断Src的长度是否满足大于等于14,小于等于32 若满足,就继续
{
v1 = strcpy_s(Str, 32u, Src); // 用strcpy_s()函数拷贝Src到Str
sub_411302(&v3 == &v3, v1, a1);
sub_411352(a1, Str); // 对Str进行异或操作 返回a1
}
return sub_411302(1, 0, a1); // 返回0 相当于return 0
}
感觉程序没有结束但就是找不到下面的代码
看了官方WP
了解到可以查看Str的引用
因为后面一直是对Str进行处理 所以可以猜测后续还会对他进行处理
点击任意一个Str 点击X 可以查看到第三条是还未分析的
我们双击进去 可以发现有两个Str
这时候我们就是该找到新Str的来源 但是我的IDA好像找不到其他引用
所以换个思路
我们可以看 unk_421008 所在区域 一般都是在一块的 点击它 按X
可以发现向上游好多引用
一个一个看 最后可以发现最上面这个 就是我们要找的
双击可以看到
那么我们就可以编写脚本解出flag
str1 = ''
str2 = 'access denieda'
flag = ''
for i in range(len(str2)):
str1 += chr(ord(str2[i])^i)
# print str1
#abafwv&cmgcnhl
for i in range(len(str2)):
if i % 3 == 0:
flag+= chr(ord(str1[i])^0x1f)
elif i % 3 == 1:
flag+= chr(ord(str1[i])^0x20)
elif i % 3 == 2:
flag+= chr(ord(str1[i])^0x21)
print flag
#~B@yWW9CLxCOwL
总结:当没有头绪的时候,可以查看变量或字符串的引用 这道题有涉及到虚函数表的知识
|