getit
程序分析
使用IDA打开程序,F5键利用HexRay工具生成可读代码如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // al
__int64 j; // [rsp+0h] [rbp-40h]
int i; // [rsp+4h] [rbp-3Ch]
FILE *stream; // [rsp+8h] [rbp-38h]
char filename[8]; // [rsp+10h] [rbp-30h]
unsigned __int64 v9; // [rsp+28h] [rbp-18h]
v9 = __readfsqword(0x28u);
LODWORD(j) = 0;
while ( (signed int)j < strlen(s) )
{
if ( j & 1 )
v3 = 1;
else
v3 = -1;
*(&t + (signed int)j + 10) = s[(signed int)j] + v3;
LODWORD(j) = j + 1;
}
strcpy(filename, "/tmp/flag.txt");
stream = fopen(filename, "w");
fprintf(stream, "%s\n", u, j);
for ( i = 0; i < strlen(&t); ++i )
{
fseek(stream, p[i], 0);
fputc(*(&t + p[i]), stream);
fseek(stream, 0LL, 0);
fprintf(stream, "%s\n", u);
}
fclose(stream);
remove(filename);
return 0;
}
从上面代码可以看出,该程序将flag储存在了
/tmp/flag.txt
的位置,然后作者很贱的又remove了这个文件,所以程序执行之后看不见。
那么,理论上只要在remove的位置加断点,然后在文件被删除之前打开就行。但实际上作者特别贱,不仅挖了remove这个坑,还通过fprintf(stream, “%s\n”, u);这条语句将flag.txt文件中的信息用覆盖了,所以即便拿到flag.txt文件也是没有用的,里面是“************”。但是无所谓,这时只要查看变量
t
处的内存就能找到flag明文。
csaw2013reversing2
程序分析
使用IDA打开程序,F5键利用HexRay工具生成可读代码如下:
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // ecx
CHAR *lpMem; // [esp+8h] [ebp-Ch]
HANDLE hHeap; // [esp+10h] [ebp-4h]
hHeap = HeapCreate(0x40000u, 0, 0);
lpMem = (CHAR *)HeapAlloc(hHeap, 8u, MaxCount + 1);
memcpy_s(lpMem, MaxCount, &unk_409B10, MaxCount);
if ( sub_40102A() || IsDebuggerPresent() )
{
__debugbreak();
sub_401000(v3 + 4, lpMem);
ExitProcess(0xFFFFFFFF);
}
MessageBoxA(0, lpMem + 1, "Flag", 2u);
HeapFree(hHeap, 0, lpMem);
HeapDestroy(hHeap);
ExitProcess(0);
}
阅读代码可知,IsDebuggerPresent()用于判断调试器是否打开,也就是说只有当调试器开启的时候才会进到if语句里面。而if里面的sub_401000函数是解密函数,所以必须要执行这个函数才能得到正确的flag。但是,解密之后程序会ExitProcess退出,因此没法执行MessageBoxA让我们看到flag的结果。
这里有两种思路,一种是通过调试,在ExitProcess处加断点,然后从内存中找到lpMem对应的flag数据。另一种是修改跳转语句,使得sub_401000执行完之后直接跳到MessageBoxA执行。
方法1
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNyZuBnLyETN1UTO1kDM1ITMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
如上图所示设置断点,开始调试后由于__debugbreak();的存在,调试程序会先断在__debugbreak处,这时点继续运行,然后选择“否”就能断到ExitProcess的位置。
这时鼠标移到lpMem上方,可以看到lpMem的值是
0x26505B8
。在Hex-View窗口中按“g”键,输入上面的地址值,就能看到flag。
方法2
如下图所示是程序的跳转关系,只需如红箭头所示将jmp指令的跳转位置修改为loc_9E10B9即可,很简单。
在
jmp short loc_9E10EF
上右键选择“keypatch->patch”,如下图所示进行修改。修改后窗口会继续跳转到下一条指令,这时关闭这个窗口就行了。
然后点击“Edit->Patch Program->Apply…”将修改应用到exe文件。
这时开调试模式运行程序就可以看到弹窗变为正确的flag了。
如果想要直接运行exe得到正常的结果,还需进行以下两处修改:
- IsDebuggerPresent下方的jz改为jnz,相当于逆转条件判断后的跳转;
- __debugbreak处会触发中断,会导致正常执行时程序奔溃,将对应的汇编指令int 3改为NOP即可,NOP为空指令,不做任何操作。