这个题目是一个64位的驱动,在ida里分析了一下。
首先找到正常的驱动分发函数里,看看这个驱动都完成什么功能。下面是驱动分发函数中,比较iocontrol code的地方。
然后进入每个处理分支,观察一下都做了什么。发现每个分支都有一个特点,满足相应的条件判断,就会将全局变量dword_148E0某位置为F。
比如: 88102004这个分支,当从ring3输入字符串为”^lejAJ]O” “MNIII” 时,会分别置dword_148E0第六位 第五位为F,两次在ring3调用DeviceIoControlcode即可。
后面的分支每次按条件要求,依次在ring3调用DeviceIoControlcode, 让驱动走完每个iocontrol code的处理分支。
注意:8810200c的分支是判断ring3的映像文件名是否含有HCTF这几个字符。
流程还需要走一个其它分支,这里就选择了0x88102014,就是jmp loc12788,这个分支会给第一位置F
接着写个ring3的程序,跑一下看看什么情况
HANDLE hDev = CreateFile("\\\\.\\Hctf",GENERIC_READ |GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,OPEN_EXISTING ,0, NULL);
DWORD code=0;
DWORD dwShellcodeSize=0x104;
char InBuf[] = "^lejAJ]O";
char mniii[]="MNIII";
char ret[]="\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3";
char OutBuf[0x100]={0};
DWORD dwRetBytes = 0;
char OutBuf2[0x100]={0};
DeviceIoControl(hDev, 0x88102004,InBuf, 0x9, OutBuf, 0x100, &dwRetBytes, 0);
DeviceIoControl(hDev, 0x88102004,mniii, 0x6, OutBuf, 0x100, &dwRetBytes, 0);
DeviceIoControl(hDev, 0x88102008,ret, 16, OutBuf, 0x100, &dwRetBytes, 0);
DeviceIoControl(hDev, 0x8810200c,ret, 16, OutBuf, 0x100, &dwRetBytes, 0);
DeviceIoControl(hDev, 0x8810200c,ret, 16, OutBuf, 0x100, &dwRetBytes, 0);
DeviceIoControl(hDev, 0x88102014,ret, 16, OutBuf, 0x100, &dwRetBytes, 0);
DeviceIoControl(hDev, 0x88102010,ret, 16, OutBuf2, 0x100, &dwRetBytes, 0);
CloseHandle(hDev);
发现驱动直接crash在下面这个call里,调用到栈上的一个地址
到这就太想吐槽了,crash在这后,发现里面有一部分代码,还有类似循环的代码,还以为要怎么补成一个计算flag的算法,尼玛最后知道就是补成栈平衡就行,真是没做过ctf啊,太天真了。。
从ring3传进来的,然后在驱动里补齐。如下图所示这段代码
需要填补上\x50\x41\x50\x48\x83\xec\x28\x59\xc3使堆栈平衡
加上hctf{}格式就是flag了
转自CSDN博客,原链接