开始正文,用NtReadVirtualMemory函数做例子
0.获取自实现函数地址
如果是自己写的函数,那就把你写入的空间首地址整过来
如果是系统自带内核函数,直接使用windbg:
就可以获得函数地址!
1.然后将该函数地址放置在第一个系统服务表的尾部
因为上图有0x11C个函数,所以我们要填充在0x11d处(尾部)
2.将函数个数+1
3.,接下来去修改函数参数字节个数表
因为原本有0-0x11b(一共0x11c个函数),现在我们在0x11c的位置添加了NtReadVirtualMemory函数,这是第0x11C个函数,所以该函数调用号为0x11C
注意,是函数参数字节个数表!!!参数总字节大小!!!
注意,是函数参数字节个数表!!!参数总字节大小!!!
注意,是函数参数字节个数表!!!参数总字节大小!!!
因为NtReadVirtualMemory有五个参数 所以这里参数个数设置为0x5*4(这里是因为每个参数大小都是4,不同函数的重新算)
4.接下来就去编写ring3 部分代码 根据11c 调用号调用该函数
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<winbase.h>
DWORD flag = 0;
void __declspec(naked) sysenter()
{
__asm
{
mov edx,esp; //sysenter函数固定的语句,在进入后sysenter会用到edx(esp)
__emit 0x0f; //sysenter硬编码
__emit 0x34;
}
}
void __declspec(naked) NtReadVirtualMemory()
{
__asm
{
mov eax,0x11c;//设置的函数调用号
call sysenter;
retn 0x14; //堆栈平衡,参数字节大小
}
}
int main()
{
DWORD a = 0x12345678;
DWORD b = 0x0;
DWORD NumberOfBytesToRead = 4;
DWORD NumberOfBytesReaded = 0;
HANDLE ProcessHandle= GetCurrentProcess();
NtReadVirtualMemory(ProcessHandle,&a,&b,NumberOfBytesToRead,&NumberOfBytesReaded);
printf("获取到的内容:%x\n",b);
printf("LastError:%x\n",flag);
flag =GetLastError();
printf("读取的字节数:%x\n",NumberOfBytesReaded);
getchar();
return 1;
}
OK,大功告成,自写API(ring3部分),再也不怕在应用层被hook了!
其他函数类比本次使用的NtReadVirtualMemory函数,熟练后可尝试
用代码去更改系统服务表,
嗯?你问我怎么用代码更改?
_KTHREAD+0xE0就是系统服务表!
嗯?你问我_KTHREAD怎么找?
进0环(这个方法很多别问我)后,FS:[0x124]找到KPCR中的KRPCB中的CurrentThread 得到<font color = red>当前线程基址 == ETHREAD结构体基址 == KTHREAD结构体基址</font>
-恭喜你,你现在找到了SSDT(系统服务表)
嗯? 你说你虽然处于0环但仍然没权限更改SSDT表内容?
- 我博客有个滴水中期检测题,第一题就是提权的代码,去吧!
: