做了这么久的pwn之后又得兼顾一下re了哈哈哈。废话不多说,这周学了动态调试器的使用,并且轻松解出了那几道题目。

linux下的动态调试器都知道,gdb永远的神,windows的动态调试器就比较各色了,ollydbgx32dbgx64dbg。这里我用的是后两个调试器,ollydbg听师傅们说是不更新了还是咋地也不知道,所以就用了x32和x64dbg,其实看了一下界面都差不多的。

动态调试注意的就是下断点,改值这一系列操作,让程序按照你想的执行。比如有一个函数就是直接输出flag,但是它直接又没有完全直接给你,那怎么办?我直接改eip去执行那个函数不就ok了?与pwn不一样,pwn我要通过漏洞去执行,这个的话文件控制权限和这台计算机的权限全部在我手上,它怎么运行我说的算,对不对?那么接下来看几道例题,这个不是说只有动调能做,但是会动调一定比不会的占优势,这是真的。

xctf-game

下载文件并且根据它的描述可以看到是一个32位PE文件且是一个类似游戏的程序,逻辑很简单,输入序列然后通过它函数的判断就可以让程序输出flag。但是

这个函数不仅复杂,直接从这里破解可以但是比较难,要从外面实现又比较苛刻那么此时我们开启动调然后直接改eip执行这个函数。

x32dbg打开查看内存映射,发现textbss的基址是0x101000

而在IDA里,此段的基址是0x401000

很清楚了,他们之间偏移了0x300000的地址大小,在IDA里面的所有地址减去0x300000就可以得到在x32dbg里的对应地址。然后注意改eip遵循的原则应该是首先保证栈尽量平衡,并且修改的幅度尽量不大。根据这个原则以及x32dbg给我们程序一开始的断点。

我们把栈顶的值修改成我们要跳转的地方,并且将eip向下调3个语句之后就能直接执行输出flag的语句而不用玩它设计的破游戏了。首先那个函数在IDA里面的地址是0x457ab4,那么在x32dbg里面这个地址就是0x157ab4。我们先把栈顶修改成这个,再把eip改成 0x77661b78

这里需要注意的是,由于我们破坏了它的栈,因此尽量避免去执行那些函数,遇到尽量跳过。

这里我们不选择执行printf函数,因为试过就知道由于之前破坏了栈帧会导致不可预估的错误发生,正确做法就是把eip改到call那个之后。

其实直接改eip也一样的,我那种只是改的其中一种方式。

然后下面还有一个prinf函数我们也选择不执行,在printf之前下个断点然后F9运行你就可以看到flag了。

然后返回游戏一看,啥也没有,但是我已经知道了flag,hhh。

1
flag:zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}

xctf-csaw2013reversing2

题目已经说了运行就可以拿flag,但是运行发现弹出来的窗口是乱码,IDA反汇编并且反编译之后检查main函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
c

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, SourceSize + 1);
memcpy_s(lpMem, SourceSize, &unk_409B10, SourceSize);
if ( !sub_40102A() && !IsDebuggerPresent() )
{
MessageBoxA(0, lpMem + 1, "Flag", 2u);
HeapFree(hHeap, 0, lpMem);
HeapDestroy(hHeap);
ExitProcess(0);
}
__debugbreak();
sub_401000(v3 + 4, lpMem);
ExitProcess(0xFFFFFFFF);
}

这也太狗了,还会检测在不在调试器中,在的话我还索性不输出了?

跟进去0x41000函数去看发现有对msgbox输出的flag做了点手脚,那么就猜测可能这个部分是用来算正确的flag的,那么我们的顺序应该是先执行那个函数再输出flag才对。所以一开始我们改eip执行0x41000函数。

直接改了eip发现并不好使,那么我们就要再main函数里面直接调用main函数的代码了。发现还是不行之后,发现int3指令一直再阻挡,因此把这个指令nop掉。发现可以直接执行那个函数,执行完了之后发现还是要退出程序,那么我们就得寻找输出这个flag的函数,为什么我们不能像上面那个题那样,直接能看到变量的值?

问得好,我也不知道qwq,只能在线寻师傅解决这个疑问了。

可以看到这边又两个调用messagebox函数,那么到底选择哪一个,回头看代码里就会发现咱们的messagebox传了四个参数,那么对比一下发现下面的messagebox才是传了四个参数的函数调用,那么我们把eip改到传参那边,运行执行跳出消息框得到flag

1
flag:flag{reversing_is_not_that_hard!}