4-权限检测

文章详细解释了裸函数的概念,强调其不包含编译器生成的额外代码,允许自定义调用规则以提高效率,适合用于shellcode。同时,文章深入讨论了RPL、CPL和DPL在段权限检查中的作用,以及不同条件下代码段、堆栈段的权限要求。通过示例代码展示了如何在裸函数中管理堆栈和进行跳转操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

裸函数

void test()
{

}

int _tmain(int argc, _TCHAR* argv[])
{
	test();
	return 0;
}

空函数,编译器替我们生成了基本结构
image.png

测试代码

//_declspec(naked) 不需要编译器替我们生成基本结构
void _declspec(naked) test()
{

}
int _tmain(int argc, _TCHAR* argv[])
{
	test();
	return 0;
}

image.png
函数下断点,转反汇编,F11进去
裸函数1.gif

发现这是编译器给我们开启了增量链接,Release版本是自动关闭的
所以我们手动关闭即可
image.png

裸函数时,编译器是不会给你生成任何的代码.
但你至少写一个ret因为在我们调用函数的时候,call xxx,push 了函数的下一条指令,所以我们在调用完函数时,要ret回去.如果不写的话,操作堆栈的时候会报错.

裸函数最大的特点就是: 所有的结构和规则是自己定的,所以我们可以自定义规则hook,效率会比一般函数高.
shellcode 可以推荐使用裸函数
一般函数都是esp或者ebp去寻址.

64位系统没有裸函数
在裸函数中去定义局部变量是会报错的,因为寻址方式没有定义,没有配置函数环境,提升堆栈,回收堆栈等问题
所以要想定义局部变量,就要手动的去配置堆栈环境

void _declspec(naked) test()
{
	__asm
	{
		push ebp;
		mov ebp, esp;
		sub esp, 0C0h;
	}
	int n;
	n = 0;
	__asm
	{
		mov esp, ebp;
		pop ebp;
		ret;
	}
}

注意: 函数范围中不允许存在初始化的局部变量
具体规则:规则和限制裸的功能

image.png

段权限检查

1827556-20200108100720748-1171197201.png
三个概念:
(1)RPL(Request Privilege Level) 请求特权级别,段选择子的后两位。
(2)DPL(Descriptor Privilege Level) 段描述特权级别,13位与14位。
(3)CPL(Current Privilege Level)当前特权级别,当前工作在CS\SS段的RPL。

区分:RPL、CPL、DPL

RPL:访问权限等级:Request Privilege Level,请求特权级别;
mov ax,001B
mov ds,ax
看我们提供的001B,转成二进制后的最后2位 //RLP是针对段选择子而言的,可以自己随便写
CPL:CPU当的特权级 看CS段SS段 //当前程序CS和SS段的权限(代码执行一定会用堆栈,就一定会用SS)
DPL:DPL段描述权限,访问该段所需要的特权级别 看段描述符的DPL字段 //DPL存储在段描述符中,规定了【访问该段所需要的特权级别是什么】

RPL访问权限等级 请求的特权级
ds段后两位

image.png

ss段后两位

image.png

DPL 段描述特权级别
CPL当前程序的特权级

当前权限等级Current Privilege Level
看CS和SS,一般看一个就够了,因为是一样的.
CS SS 最后两位决定你在哪个环上
CS和SS中,存储的【段选择子后2位】
如:
001B: 0000 0000 0001 1011 后两位为11,值为3–>当前的程序处于3环
0008: 0000 0000 0000 0100 后两位为00,值为0–>当前程序处于0环
image.png

image.png

一、实验数据段的 权限

条件:CPL <= DPL (当前程序权限是否足够) 并且RPL<=DPL (段选择子请求的权限是否足够) (数值越大,权限越小)
image.png
执行以下该代码
image.png
不会发生异常

二、实验堆栈段的权限

条件:CPL = RPL = DPL
**代码段条件也一样 **

image.png
执行以下该代码
image.png
发生异常
image.png

三、实验代码段权限

条件:CPL = RPL = DPL
image.png
假设此处是代码段,不是调用门之类的 区分是一致代码段还是非一致代码段
①非一致代码段要求:CPL=DPL且RPL<=DPL
②一致代码段要求: CPL>=DPL
能修改,但不会提权,也不会抛异常
image.png

四、实验 jmp call ret

jmp

image.png

void _declspec(naked) test1()		
{		
	__asm	
	{	
		
		//jmp eax;
		//retf;
	}	
}		
		
		
		
int _tmain(int argc, _TCHAR* argv[])		
{		
	printf("%x\r\n",test1);	
		
	__asm	
	{	
		
	}	
	system("pause");	
	return 0;	
}		

image.png
image.png
打印的地址是随机的,我们要将该设置关闭
image.png

image.png

void _declspec(naked) test1()			
{			
	__asm		
	{		
			
	}		
}			
			
			
			
int _tmain(int argc, _TCHAR* argv[])			
{			
	printf("%x\r\n",test1);		
			
	__asm		
	{		
		//微软并不支持该写法	
		// jmp far 0x48:401000	
	}		
	system("pause");		
	return 0;		
}			



void _declspec(naked) test1()				
{				
				
}				
				
int _tmain(int argc, _TCHAR* argv[])				
{				
	printf("%x\r\n",test1);			
	char bufcode[] = {0,0,0,0,0x48,0};			
	*(int *)&bufcode[0] = (ULONG)test1;			
	__asm			
	{			
		//微软并不支持该写法		
		// jmp far 0x48:401000		
		jmp fword ptr bufcode;		
	}			
	system("pause");			
	return 0;			
}				
				
				
				


CS段修改成功
image.png

那么如何返回去呢?

void _declspec(naked) test1()				
{				
	__asm			
	{			
		pop eax;		
		jmp eax;		
	}			
}				
				
int _tmain(int argc, _TCHAR* argv[])				
{				
	printf("%x\r\n",test1);			
	char bufcode[] = {0,0,0,0,0x48,0};			
	*(int *)&bufcode[0] = (ULONG)test1;			
	__asm			
	{			
		lea eax,[haha]		
		push eax;		
		jmp fword ptr bufcode;		
haha:				
				
	}			
	system("pause");			
	return 0;			
}				

如何证明提权?

如果你能访问到内核地址,那么你就提权了,
不能提权的原因是:不能同时修改CS和SS

void _declspec(naked) test1()					
{					
	__asm				
	{				
		mov eax,0x80b99000;			
		mov eax,dword ptr [eax];			
		//mov eax,dword ptr ds:[0x80b99000];			
		pop eax;			
		jmp eax;			
	}				
}					
					
int _tmain(int argc, _TCHAR* argv[])					
{					
	printf("%x\r\n",test1);				
	char bufcode[] = {0,0,0,0,0x48,0};				
	*(int *)&bufcode[0] = (ULONG)test1;				
	__asm				
	{				
		lea eax,[haha]			
		push eax;			
		jmp fword ptr bufcode;			
haha:					
					
	}				
	system("pause");				
	return 0;				
}					

image.png

跨段不提权远跳转

image.png

	void _declspec(naked) test1()				
	{				
		__asm			
		{			
					
			ret;		
		}			
	}				
					
	int _tmain(int argc, _TCHAR* argv[])				
	{				
		printf("%x\r\n",test1);			
		char bufcode[]={0,0,0,0,0x48,0};			
		*(int *)&bufcode[0] = (ULONG)test1;			
		__asm			
		{			
			call  fword ptr bufcode;		
	haha:				
					
		}			
		system("pause");			
		return 0;			
	}				

image.png

image.png
image.png

正常来说 esp提升堆栈应该是0012FE4C,那为什么是0012FE48呢?

image.png
多了个1B
多压了个CS段
导致堆栈不平衡
image.png

使用retf可以实现原跳转,不会报错

void _declspec(naked) test1()				
{				
	__asm			
	{			
				
		retf;		
	}			
}				
				
int _tmain(int argc, _TCHAR* argv[])				
{				
	printf("%x\r\n",test1);			
	char bufcode[]={0,0,0,0,0x48,0};			
	*(int *)&bufcode[0] = (ULONG)test1;			
	__asm			
	{			
		call  fword ptr bufcode;		
haha:				
				
	}			
	system("pause");			
	return 0;			
}				

image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑桃鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值