9-调用门(无参)

1. 概述

本篇,将真正的实现提权——当前特权级从 3 变为 0.

当然,CPU 不会让你就这么简单的从 3 环跨到 0 环。但是,CPU 又必须提供一套方法,来让你完成这个功能。

前面讲过。DPL = 0 的非一致代码段,是绝对不允许不同特权级的程序跳转进来。可是,我给以给你开个后门,让你进来,然后给你最高权限,允许你胡作非为。

这个后门,必须由我(操作系统)来指定,而且只允许你跳转到我指定的地方。

2. 调用门

前面做过 jmp 跨段实验,但是 jmp 跨段后,权限是不会变的。CPU 提供给了我们另一种方法——调用门,来达到提权的目的。可以使用 call + 调用门的段选择子,来达到提权的目的。通过调用门,可以让 3 环程序进入 0 环,也就是由用户态变成内核态。

  • call far 指令格式
call far cs:eip

由于在 VC6.0 中不支持这种写法,所以可以写成下面这种形式。(buffer是一个长度为6字节的缓冲区,高2字节存放 cs 段选择子,低 4 字节存放偏移值。)

__asm {
  call fword ptr [buffer]
}

实际上,call far 后面跟的 eip 已经废弃。

下面的实验演示了如何读取高 2G 内存。

3. 编写 r0 函数 getData

  • 该函数将运行在ring 0下,因为其中读取了高2G内存数据。
  • 在 main 函数执行长调用,注意VC6.0 不能直接写 call 0x48:0,编译不通过
#include <windows.h>
#include <stdio.h>

WORD g_cs0, g_ss0, g_ds0, g_es0, g_fs0, g_gs0;
DWORD r0_data_lowdword, r0_data_hidword;

__declspec(naked) void getData() {
	__asm {
		pushfd
		pushad
		mov g_cs0, cs
		mov g_ss0, ss
		mov g_ds0, ds
		mov g_es0, es
		mov g_fs0, fs
		mov g_gs0, gs
		mov eax, 0x8003f048
		mov eax, [eax]
		mov r0_data_lowdword, eax
		mov eax, 0x8003f04c
		mov eax, [eax]
		mov r0_data_hidword, eax
		popad
		popfd
		retf
	}
}

void printData() {
	printf("g_cs0=%02x\ng_ss0=%02x\ng_ds0=%02x\ng_es0=%02x\ng_fs0=%02x\ng_gs0=%02x\nr0_data(0x8003f048)=%08x %08x\n", 
		g_cs0, g_ss0, g_ds0, g_es0, g_fs0, g_gs0, r0_data_hidword, r0_data_lowdword);
}

int main(int argc, char* argv[]) {
	char cs_eip[6] = {0, 0, 0, 0, 0x48, 0};// 这里的 eip 被废弃
	__asm {
		call fword ptr [cs_eip]
	}
	printData();
	getchar();
	return 0;
}

有一点需要注意的是,call far 函数指令的格式虽然是 call far cs:eip,但是这后面的 eip 已经被废弃。而真正的 eip 是填写到了调用门中。

4. 查看函数 getData 地址

  • 在 main 函数第一行下断点,F5 运行调试,然后在函数 getData 中右键,查看反汇编
    这里写图片描述

5. 构造调用门描述符

  • 调用门描述符结构
|   7    |     6  |     5     |    4    |   3    |   2    |   1    |   0    |  字节
|76543210|76543210|7 65 4 3210|765 43210|76543210|76543210|76543210|76543210|  比特
|-----------------|1|--|0|1100|000|-----|--------|--------|--------|--------|  占位
|offset in segment|P|D |S|TYPE|   |param|segment selector |offset in segment|  含义
|     31-16         |P |          |nums |                 |       15-0      |
                    |L |
  • 函数地址是 00401030,构造的调用门描述符是 0040ec00`00081030
  • 在 WinDbg 调试器中,执行 eq 命令安装描述符
    这里写图片描述

6. 运行结果

这里写图片描述

7. 总结

调用门虽然是 CPU 提供给使用者提权的一种手段,但是 Windows 中却并未使用。在 Windows 中,大量使用了中断门来进行提权,包括后面的系统调用,都是采用中断的方式实现。

另外,所谓的后门,其实有很多,比如中断门,陷阱门,任务门。它们都可以实现提权。后续文章会陆续讲解。

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
### 回答1: 可以使用以下代码实现: ``` public class ScoreCalculator { public static double calculateAverage(double score1, double score2) { return (score1 + score2) / 2; } } ``` 在调用该方法时,可以将两课程的成绩作为参数传入,例如: ``` double score1 = 80; double score2 = 90; double average = ScoreCalculator.calculateAverage(score1, score2); System.out.println("The average score is: " + average); ``` 输出结果为: ``` The average score is: 85.0 ``` ### 回答2: 编写一个Java方法来计算两课程考试成绩的平均分,可以通过方法的参数传入成绩信息。以下是一个可能的实现: ```java public class AverageCalculator { public static double calculateAverage(double score1, double score2) { double average = (score1 + score2) / 2.0; return average; } public static void main(String[] args) { double score1 = 80.5; // 第一课程成绩 double score2 = 90.0; // 第二课程成绩 double averageScore = calculateAverage(score1, score2); System.out.println("两课程的平均分是:" + averageScore); } } ``` 上述代码定义了一个`calculateAverage`方法来接收两个成绩作为参数,并返回这两课程的平均分。在`main`方法中,我们传入两个具体的成绩数值,然后调用`calculateAverage`方法来计算平均分,并将结果打印输出。 假设第一课程的成绩是80.5,第二课程的成绩是90.0,然后通过调用`calculateAverage`方法计算得出的平均分是85.25(取小数点后两位)。 ### 回答3: Java是一种面向对象的编程语言,可以使用它编写带参方法来计算两课程的考试成绩平均分。以下是一个简单的示例: ```java public class ScoreCalculator { public static void main(String[] args) { double mathScore = 85.5; // 数学成绩 double englishScore = 78.5; // 英语成绩 double averageScore = calculateAverageScore(mathScore, englishScore); System.out.println("平均成绩为:" + averageScore); } public static double calculateAverageScore(double score1, double score2) { double average = (score1 + score2) / 2; return average; } } ``` 在这个例中,`calculateAverageScore`方法接收两个参数:`score1`和`score2`,分别表示两课程的考试成绩。方法内部计算这两课程成绩的平均值并返回。 在`main`方法中,我们定义了两个变量`mathScore`和`englishScore`作为成绩输入,然后调用`calculateAverageScore`方法,并将返回的平均分打印出来。 这样,你就可以通过方法的参数传入成绩信息,并使用带参方法来计算两课程考试成绩的平均分了。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值