静态调试方法
看题目描述,说是运行就能拿到flag,下载运行一下,看来不行
先查一下有没有加壳,这个没有加壳,而且是个32位的程序
用IDA32位打开,f5查看伪代码
接下来就是分析代码了
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, (int)lpMem);
ExitProcess(0xFFFFFFFF);
}
MessageBoxA(0, lpMem + 1, "Flag", 2u);
HeapFree(hHeap, 0, lpMem);
HeapDestroy(hHeap);
ExitProcess(0);
}
先查一下HeapCreate()和HeapAlloc()是干啥的
这两条语句是申请了一个大小为Maxcount = 24h的空间
然后通过字符串拷贝函数memcpy_()将 &unk_409B10中的内容拷贝到lpMem中
接下来是这个if语句
if ( sub_40102A() || IsDebuggerPresent() )
{
__debugbreak();
sub_401000(v3 + 4, (int)lpMem);
ExitProcess(0xFFFFFFFF);
}
sub_40102A() 函数返回的直接就是0,所以不用管
IsDebuggerPresent() 是一个检测程序是否被调试的函数,如果检测到被调试,则会直接退出,我还试了下
这反调试反了个寂寞
那就先跳过这个直接看后面的语句
MessageBoxA(0, lpMem + 1, "Flag", 2u);
这是个输出语句,结合之前弹出的窗口,推出flag就在plMem里面
写了个脚本来输出内容
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int lpMem[37] = {0x0BB,0x0CC,0x0A0,0x0BC,0x0DC,0x0D1,0x0BE,0x0B8,0x0CD,0x0CF,
0x0BE,0x0AE,0x0D2,0x0C4,0x0AB,0x82,0x0D2,0x0D9,0x93,0x0B3,0x0D4,0xDE,
0x93,0x0A9,0x0D3,0x0CB,0x0B8,0x82,0x0D3,0x0CB,0x0BE,0x0B9,0x9A,0x0D7,
0x0CC,0x0DD};
for(int i = 0 ; i < 36; i++)
{
printf("%c",lpMem[i]);
}
return 0;
}
运行出来是乱码(废话)
那唯一还没看的地方就是之前的那个if语句中的内容了
里面有个sub_401000函数用了lpMem作为参数,跟进去查看
if ( sub_40102A() || IsDebuggerPresent() )
{
__debugbreak();
sub_401000(v3 + 4, (int)lpMem);
ExitProcess(0xFFFFFFFF);
}
v2=dword_409B38
然后看这个循环,前面result的值可以不用管,反正也不会超过这个字符串的长度36
然后天真的我以为这个是隔四个异或一次v2,结果输出的还是乱码
然后我发现了将这个转换下类型会变成四个数。。
那个循环应该是依次异或v2中的数,,,根据这个可以写出脚本
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int lpMem[37] = {0x0BB,0x0CC,0x0A0,0x0BC,0x0DC,0x0D1,0x0BE,0x0B8,0x0CD,0x0CF,
0x0BE,0x0AE,0x0D2,0x0C4,0x0AB,0x82,0x0D2,0x0D9,0x93,0x0B3,0x0D4,0xDE,
0x93,0x0A9,0x0D3,0x0CB,0x0B8,0x82,0x0D3,0x0CB,0x0BE,0x0B9,0x9A,0x0D7,
0x0CC,0x0DD};
int v2[4] = {0xBB,0XAA,0XCC,0XDD};
for(int i = 0 ; i < 36; i++)
{
printf("%c",lpMem[i] ^ v2[ i % 4]);
}
return 0;
}
运行得到结果
动态调试方法
.用OLLYDDEBUG打开
按F8一直运行,直到看到这个函数,之前查到了这是个反调试的函数,对照这就是if语句中的判断过程
if ( sub_40102A() || IsDebuggerPresent() )
{
__debugbreak();
sub_401000(v3 + 4, (int)lpMem);
ExitProcess(0xFFFFFFFF);
}
看到调用这个语句的上面还有一个jnz语句,而且跳转还未实现,那这个应该就是if语句中的 || ,因为前面返回的是0,所以要继续判断||右边的值
往下看,这里有一个大的跳转,这个大跳转跳完后就直接停止程序,所以双击两下把这个指令改成jnz
这里还有一个int3指令,int3会引发一个中断,所以要把这个改成nop(意思是什么都不做)
改完后的指令
继续按F8执行,又看到一个jmp指令,直接跳转到结束程序,这个对应的就是 debugbreak(),所以继续把它改成nop
__debugbreak();
sub_401000(v3 + 4, (int)lpMem);
ExitProcess(0xFFFFFFFF);
继续往下看,又是一个jmp指令,这里对应的是 ExitProcess(0xFFFFFFFF),同样的把它改成nop
__debugbreak();
sub_401000(v3 + 4, (int)lpMem);
ExitProcess(0xFFFFFFFF);
改完后的指令,这里改完后会自动变成两个nop,我也不知道为啥
然后按F8继续运行就行,运行到这里的时候会弹出来一个空白的框,随便点一个按钮然后继续运行就行
继续运行,flag已经出来了