这是一个CTF的逆向题,考点为:1.64位upx手工脱壳。2.魔改XTEA。
首先用EXEINFO查看一下程序的基本信息:

Win64程序,加了upx壳。
尝试运行一下:

运行可以看到提示输入flag的字符串。
基本信息收集完,下面开始解题:
使用命令upx -d对程序进行脱壳,发现脱壳失败了。

这里有两种解决方案。
方案一:(使用文件查看工具打开看段)

这里是将UPX修改成了uPX,将其修改回来,重新upx -d就可以看到脱壳成功了。

方案二:(手动脱壳)
用x64dbg打开文件,然后停到EP处

我们可以利用rsp定律,对程序下断点找到pop处的地址,这里我没有使用下断点的方式来定位,直接往下翻就可以找到了。

这里的经过一系列的弹栈操作之后jmp跳转到了一个较远的代码处,jmp的地址就是OEP所在的位置,下个断点直接跟过去。下面就是程序的OEP了。

使用x64dbg自带的scylla插件,对解压好的程序进行dump。

将程序保存完后:

点击第一步插件会自动搜索IAT,如果显示下图就代表找到了程序的IAT表

然后直接点击获取导入就会在上面显示找到的导入表

这里可以看到有一个表没有导出成功,一开始我是直接点击修复转储将这四个表都导入到了dump下来的程序里面,程序虽然不能运行但是不影响IDA调试,但是后面听别的师傅直接删除这个导出失败的表,就可以正常运行了

修复完后可以看到文件夹下多了两个程序,第二个是导出但没有修复IAT的程序,第三个是基于导出的源程序修复好了IAT。双击是可以直接运行的。
根据提示可知这个程序使用的是TEA系列的加密算法,用IDA打开可以直接查看,先对主函数进行分析。
int __cdecl main(int argc, const char **argv, const char **envp)
{
uint32_t key[4]; // [rsp+20h] [rbp-90h] BYREF
uint32_t flag[8]; // [rsp+30h] [rbp-80h] BYREF
char tmp[32]; // [rsp+50h] [rbp-60h] BYREF
char str[38]; // [rsp+70h] [rbp-40h] BYREF
int i_1; // [rsp+A4h] [rbp-Ch]
int i_0; // [rsp+A8h] [rbp-8h]
int i; // [rsp+ACh] [rbp-4h]
_main(argc, argv, envp);
if ( IsDebuggerPresent() )
{
puts("Do not debug me!!!!");
exit(-1);
}
printf("input the flag:");
scanf("%38s", str); // 接收用户输入的flag
if ( str[0] != 'f' && str[1] != 'l' && str[2] != 'a' && str[3] != 'g' && str[4] != '{' && str[37] != '}' )// 对输入的flag格式进行判断
exit(-1);
memset(tmp, 0, sizeof(tmp));
strncpy(tmp, &str[5], 0x20ui64); // 截取flag的有效数据
for ( i = 0; i <= 31; i += 4 ) // 将flag的有效数据以XTA加密每次加密长度进行规整
flag[i / 4] = (tmp[i + 2] << 8) + (tmp[i + 1] << 16) + (tmp[i] << 24) + tmp[i + 3];
qmemcpy(key, "I love dreak tea", sizeof(key));// xtea的密钥为字符串“I love dreak tea”
for ( i_0 = 0; i_0 <= 7; i_0 += 2 )
xtea_encipher(&flag[i_0], key); // 调用加密函数对数据进行加密
for ( i_1 = 0; i_1 <= 7; ++i_1 ) // 循环比对,判断输入的flag是否正确
{
if ( enc[i_1] != flag[i_1] )
exit(-1);
}
printf("You got the flag!!!");
return 0;
}
接着是加密函数的分析,下面主要列出魔改的地方。
**void __cdecl encipher(uint32_t *v, uint32_t *key)
{
uint32_t sum; // [rsp+20h] [rbp-10h]
uint32_t v1; // [rsp+24h] [rbp-Ch]
uint32_t v0; // [rsp+28h] [rbp-8h]
unsigned int i; // [rsp+2Ch] [rbp-4h]
v0 = *v;
v1 = v[1];
sum = 0;
if ( IsDebuggerPresent() )
{
puts("Do not debug me!!!!");
exit(-1);
}
for ( i = 0; i <= 0xF; ++i )
{
v0 += (v1 + ((v1 >> 5) ^ (16 * v1))) ^ (key[sum & 3] + sum);
sum -= 559038737; // 魔改处1:delta的值有改变
v1 += (v0 + ((v0 >> 5) ^ (16 * v0))) ^ (key[(sum >> 11) & 3] + sum);
*key ^= salt[0]; // 魔改处2:多加了一个对密钥的异或修改
key[1] ^= salt[1];
key[3] ^= salt[2];
key[4] ^= salt[3];
}
*v = v0;
v[1] = v1;
}**