先观察代码
可以得到一个类似结构得链表,如果在这里溢出修改pNext的话,因为fscanf结束后,还有pNode->pNext = pHead,会还原回去所以这里不行。
这句代码的作用就是输入,没用写入的机会,所以也没用
而这两句代码能够溢出数据,并且不会被写回,这里解释下为什么非要溢出改pNext,如果仅仅只是溢出数据,那么任何一个fscanf(fp, "%s", pNode->szName);
这样的写法都能够随便溢出,但是我们缺少能够执行我们shellcode的机会。第一个fscanf
修改我们要第二次要写入数据的位置。第二个fscanf
会写入第二次数据,这次我们把数据写到哪里,能够有机会执行,又能够有写的权限?
继续看,下面调用了两个函数,printf
,fclose
例如:printf
里面会调用WriteFile
和ReadFile
等api
fclose
会调用CloseHandle
等api,感兴趣的话可以OD自己跟进去看
如果这些api通过IAT表调用的话,那么我们第二次写入的shellcode放入api在IAT表的地址,那么不就会执行到我们的shellcode吗?
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <iostream.h>
struct tagNode
{
char szName[8];
struct tagNode *pNext;
};
struct tagTest
{
short Magic;
short nLength;
char *szBuf;
};
void test(char *szPwd)
{
tagNode *pHead = NULL;
tagNode *pNode = NULL;
FILE *fp = NULL;
fp = fopen("name.txt", "r+");
if (fp == NULL)
{
exit(-1);
}
int nRet = EOF;
for (int i = 0; i < 3; i++)
{
pNode = new struct tagNode;
nRet = fscanf(fp, "%s", pNode->szName);
pNode->pNext = pHead;
pHead = pNode;
}
for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
{
printf("%s\r\n", pNode->szName);
}
pNode = pHead;
fscanf(fp, "%s", pNode->szName);
pNode = pHead->pNext;
fscanf(fp, "%s", pNode->szName);
for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
{
printf("%s\r\n", pNode->szName);
}
if (fp)
{
fclose(fp);
fp = NULL;
}
}
int main(int argc, char* argv[])
{
char szPwd[] = "Hello";
test(szPwd);
system("pause");
return 0;
}
for (int i = 0; i < 3; i++)
{
pNode = new struct tagNode;
nRet = fscanf(fp, "%s", pNode->szName);
pNode->pNext = pHead;
pHead = pNode;
}
for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
{
printf("%s\r\n", pNode->szName);
}
pNode = pHead;
fscanf(fp, "%s", pNode->szName);
pNode = pHead->pNext;
fscanf(fp, "%s", pNode->szName);
for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
{
printf("%s\r\n", pNode->szName);
}
if (fp)
{
fclose(fp);
fp = NULL;
}
00430250 >76C83ED3 kernel32.ReadFile
-
先观察代码
可以得到一个类似结构得链表,如果在这里溢出修改pNext的话,因为fscanf结束后,还有pNode->pNext = pHead,会还原回去所以这里不行。
for (int i = 0; i < 3; i++)
{
pNode = new struct tagNode;
nRet = fscanf(fp, "%s", pNode->szName);
pNode->pNext = pHead;
pHead = pNode;
}
这句代码的作用就是输入,没用写入的机会,所以也没用
for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
{
printf("%s\r\n", pNode->szName);
}
而这两句代码能够溢出数据,并且不会被写回,这里解释下为什么非要溢出改pNext,如果仅仅只是溢出数据,那么任何一个fscanf(fp, "%s", pNode->szName);
这样的写法都能够随便溢出,但是我们缺少能够执行我们shellcode的机会。第一个fscanf
修改我们要第二次要写入数据的位置。第二个fscanf
会写入第二次数据,这次我们把数据写到哪里,能够有机会执行,又能够有写的权限?
pNode = pHead;
fscanf(fp, "%s", pNode->szName);
pNode = pHead->pNext;
fscanf(fp, "%s", pNode->szName);
继续看,下面调用了两个函数,printf
,fclose
例如:printf
里面会调用WriteFile
和ReadFile
等api
fclose
会调用CloseHandle
等api,感兴趣的话可以OD自己跟进去看
如果这些api通过IAT表调用的话,那么我们第二次写入的shellcode放入api在IAT表的地址,那么不就会执行到我们的shellcode吗?
for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
{
printf("%s\r\n", pNode->szName);
}
if (fp)
{
fclose(fp);
fp = NULL;
}
- 进入printf函数查看间接调用的API
看到了WriteFile
也可以用访问断点来查看是否调用
发现有间接访问
记录下00430250 >76C83ED3 kernel32.ReadFile
- 编写读入的数据
fscanf遇到\x0D\x0A\x0C....会被截断
第一个循环构造的链表
![]
接下来是我们定位的溢出位置的第一次执行,把ReadFile
IAT地址给写进去
crtl+g过去看发现是我们api地址
写进去了但是崩溃了为什么呢?
因为call 这个地址跳过去一个不对的地址肯定崩
红框就是填写shllecode地址,正好是写入位置+4
在这个地址下硬件执行断点,发现可以来一切正常
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-12-27 08:35
被自然dashen编辑
,原因: