Windows系统调用中API的3环部分(依据分析重写ReadProcessMemory函数)
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html
Windows系统调用中API的3环部分
一、R3环API分析的重要性
- Windows所提供给R3环的API,实质就是对操作系统接口的封装,其实现部分都是在R0实现的。
- 很多恶意程序会利用钩子来钩取这些API,从而达到截取内容,修改数据的意图。
- 现在我们使用olldbg对ReadProcessMemory进行跟踪分析,查看其在R3的实现,并根据我们的分析来重写一个ReadProcessMemory。
- 重写ReadProcessMemory之后,这就会加大恶意代码截获的难度。
- 当然,对于自己来说也有很多弊端,比如只能在指定的操作系统中运行(32位与64位操作系统,其运行ReadProcessMemory的执行动作是不一样的,在64位运行32位程序,其中间会调用wow64cpu.dll来进行转换)
二、调试代码
#include "pch.h"
#include <iostream>
#include <algorithm>
#include <Windows.h> int main() {
getchar();
getchar();
int a[],t;
printf("hello world!");
getchar();
getchar();
// 依次往 p 指针中写入数据,再用ReadProcessMemory读取数据
for (int i = ; i < ; i++) {
WriteProcessMemory(INVALID_HANDLE_VALUE, &a[i], &i, sizeof(int),NULL); }
for (int i = ; i < ; i++) {
ReadProcessMemory(INVALID_HANDLE_VALUE, &a[i], &t, sizeof(int), NULL);
printf("%d\n", t);
}
getchar();
getchar(); }
三、调试中的关键汇编代码(系统环境:在Windows7 32位操作系统 / 调试器:olldbg)
1. 在exe 中 调用 kernel32.ReadProcessMemroy函数
01314E3E 8BF4 mov esi,esp
01314E40 6A 00 push 0x0
01314E42 6A 04 push 0x4
01314E44 8D45 DC lea eax,dword ptr ss:[ebp-0x24]
01314E47 50 push eax
01314E48 8B4D C4 mov ecx,dword ptr ss:[ebp-0x3C]
01314E4B 8D548D E8 lea edx,dword ptr ss:[ebp+ecx*4-0x18]
01314E4F 52 push edx
01314E50 6A FF push -0x1
01314E52 FF15 64B0310>call dword ptr ds:[<&KERNEL32.ReadProcessMemory>]; kernel32.ReadProcessMemory
01314E58 3BF4 cmp esi,esp
2. 在 kernel32.ReadProcessMemroy函数 中调用 jmp.&API-MS-Win-Core-Memory-L1-1-0.ReadProcessMemory> 函数
// 该函数相当于什么也没做...
7622C1CE > 8BFF mov edi,edi
7622C1D0 55 push ebp
7622C1D1 8BEC mov ebp,esp
7622C1D3 5D pop ebp ;
7622C1D4 ^ E9 F45EFCFF jmp <jmp.&API-MS-Win-Core-Memory-L1-1-0.ReadProcessMemory>
3. 在 API-MS-Win-Core-Memory-L1-1-0.ReadProcessMemo 中调用 KernelBa.ReadProcessMemory 函数
761F20CD - FF25 0C191F7>jmp dword ptr ds:[<&API-MS-Win-Core-Memory-L1-1-0.ReadProcessMemo>; KernelBa.ReadProcessMemory
4. 在KernelBa.ReadProcessMemory 调用 <&ntdll.NtReadVirtualMemory> 函数
75DA9A0A > 8BFF mov edi,edi
// 这两部分在编写函数时就会使用
75DA9A0C 55 push ebp
75DA9A0D 8BEC mov ebp,esp
75DA9A0F 8D45 14 lea eax,dword ptr ss:[ebp+0x14]
75DA9A12 50 push eax
75DA9A13 FF75 14 push dword ptr ss:[ebp+0x14]
75DA9A16 FF75 10 push dword ptr ss:[ebp+0x10]
75DA9A19 FF75 0C push dword ptr ss:[ebp+0xC]
75DA9A1C FF75 08 push dword ptr ss:[ebp+0x8]
75DA9A1F FF15 C411DA7>call dword ptr ds:[<&ntdll.NtReadVirtualMemory>] ; ntdll.ZwReadVirtualMemory
5. 在 <&ntdll.NtReadVirtualMemory> 中调用 ntdll.KiFastSystemCall 函数
77A162F8 > B8 15010000 mov eax,0x115 // 对应操作系统内核中某一函数的编号。
77A162FD BA 0003FE7F mov edx,0x7FFE0300 // 该地方是一个函数,该函数决定了什么方式进零环。
77A16302 FF12 call dword ptr ds:[edx] ; ntdll.KiFastSystemCall
6. 在 ntdll.KiFastSystemCall 中 调用sysenter
77A170B0 > 8BD4 mov edx,esp
77A170B2 0F34 sysenter
77A170B4 > C3 retn
四、汇编代码分析解读(根据三中的序号依次解读)
- 这部分是我们程序中调用ReadProcessMemory后编译器直接编译后的汇编代码,传入参数与API调用
- 在kenel32.dll中,mov edi,edi 是用于热补丁技术所保留的(函数开始处的MOV EDI, EDI的作用),这段代码仔细看其实除了jmp什么也没干。
- 转到kernelBase.dll中实现ReadProcessMemory。
- 这段汇编代码,将ReadProcessMemory中传入的参数再次入栈,调用ntdll.ZwReadVirtualMemory函数。
- 这段汇编代码看注释,eax中存放了一个编号,其就是在内核中的ReadProcessMemory实现;在 0x7FFE0300 处存放了一个函数指针,该函数指针决定了以什么方式进入0环(中断/快速调用)。
- 在ntdll.KiFastSystemCall调用sysenter。
五、重写ReadProcessMemory函数的思路
我们所看到的汇编代码,本质就是Windows所执行的步骤,我们依据上面的分析,完全可以重新写一个该函数,只需要关键部分。
1) 退而求其次
我们希望可以在自己的代码中直接使用 "sysenter",但经过编写发现其并没有提供这种指令。
因此在"sysenter"无法直接使用的情况下,只能退而求其次,调用ntdll.KiFastSystemCall函数。
2)传递参数,模拟call指令
ntdll.KiFastSystemCall函数需要借助ntdll.NtReadVirtualMemory传递过来的参数,然后执行call指令。
我们并不希望执行call指令执行,因为执行call指令意味着又上了一层。(多一层被钩取的风险)
我们希望自己的代码中直接传递参数,并且直接调用调用ntdll.KiFastSystemCall函数。
因此我们需要模拟call指令。call指令的本质就是将返回地址入栈,并跳转。我们不需要跳转,只需要将返回地址入栈(四个字节 使用 sub esp,4 模拟)
3)手动实现栈平衡
我们内嵌汇编代码后,需要手动平衡栈,我们只需要分析esp改变了多少(push、pop以及直接对esp的计算)。
经过分析共减少了24字节,所以代码最后应该有 add esp,24 来平衡栈。
六、ReadProcessMemory函数重写的实现(重点看汇编代码)
该代码是使用快速调用所编写的,如果想使用中断实现调用内核函数,请移步这里:Windows系统调用中API从三环到零环(下)
(执行结果)
#include "pch.h"
#include <iostream>
#include <algorithm>
#include <Windows.h>
void ReadMemory(HANDLE hProcess, PVOID pAddr, PVOID pBuffer, DWORD dwSize, DWORD *dwSizeRet)
{ _asm
{
lea eax, [ebp + 0x14]
push eax
push[ebp + 0x14]
push[ebp + 0x10]
push[ebp + 0xc]
push[ebp + ]
sub esp,
mov eax, 0x115
mov edx, 0X7FFE0300 //sysenter不能直接调用,我间接call的
CALL DWORD PTR[EDX]
add esp, }
}
int main()
{
HANDLE hProcess = ;
int t = ;
DWORD pBuffer;
//hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0,a);
ReadMemory((HANDLE)-, (PVOID)&t, &pBuffer, sizeof(int), );
printf("%X\n", pBuffer);
ReadProcessMemory((HANDLE)-, &t, &pBuffer, sizeof(int), );
printf("%X\n", pBuffer); getchar();
return ;
}
Windows系统调用中API的3环部分(依据分析重写ReadProcessMemory函数)的更多相关文章
- Windows系统调用中API从3环到0环(下)
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API从3环到0环(下) 如果对API在 ...
- Windows系统调用中API从3环到0环(上)
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API从3环到0环(上) 如果对API在三 ...
- Windows系统调用中的系统服务表描述符
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中的系统服务表描述符 在前面,我们将解过 ...
- Windows系统调用中的现场保存
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中的现场保存 我们之前介绍过三环进零环的步骤 ...
- Windows系统调用中的系统服务表
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中的系统服务表 如果这部分不理解,可以查看 ...
- windows进程中的内存结构(好多API,而且VC最聪明)
在阅读本文之前,如果你连堆栈是什么多不知道的话,请先阅读文章后面的基础知识. 接触过编程的人都知道,高级语言都能通过变量名来访问内存中的数据.那么这些变量在内存中是如何存放的呢?程序又是如何使用这 ...
- 详解 UWP (通用 Windows 平台) 中的两种 HttpClient API
UWP (通用 Windows 平台) 应用开发者在构建通过 HTTP 与 Web 服务或服务器断点交互的应用时,有多种 API 可以选择.要在一个托管 UWP 应用中实现 HTTP 客户端角色,最常 ...
- 《程序员的自我修养》读书笔记——系统调用、API
系统调用 程序运行的时候,本身是没有权限访问多少系统资源的.系统资源有限,如果操作系统不进行控制,那么各个程序难免会产生冲突.线程操作系统都将可能产生冲突的系统资源保护起来,阻止程序直接访问. ...
- Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取
为什么要写这篇文章 1. 因为最近在学习<软件调试>这本书,看到书中的某个调试历程中讲了Windows的系统调用的实现机制,其中讲到了从Ring3跳转到Ring0之后直接进入了K ...
随机推荐
- oracle用imp导入dmp文件
oracle命令行登录 sqlplus 用户名/密码 创建用户 create user 用户 identified by 密码 ; 创建表空间 create tablespace 表空间名 dataf ...
- 【原创】(四)Linux内存模型之Sparse Memory Model
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- SSM相关面试题(简答)
1.springmvc的执行 流程: 2.mybstis的执行流程: 3.ioc和DI的理解: 4.对aop的理解: 5.spring中常见的设计模式: 6.spring中声明式事务处理的配置: ...
- CTF常用软件/工具
慢慢更新 整合版: http://www.jz5u.com/Soft/Progra/tool/163275.html/ 各种在线工具以及工具整合 http://www.ctftools.com/ 逆向 ...
- Day 23 系统服务之救援模式
1.CentOS6与Centos 7启动流程 4.运行级别C6&C7 0 关机 1 单用户模式 (超级权限 必须面对实体硬件) 2 暂未使用 3 字符界面(黑框) 4 暂未使用 5 图形界面 ...
- js vue 页面添加水印
vue 微信页面添加水印 this.$nextTick(function() { watermark({ watermark_txt ...
- Rsync 服务部署与参数详解
Rsync 简介 rsync 是一款开源的.快速的.多功能的.可实现全量及增量的本地或远程数据同步备份的优秀工具.Rsync软件适用于unix/linux/windows等多种操作系统平台. 传统的 ...
- C++中类型强制转换
C++中强制类型转换有四种: 1.static_cast 格式:static_cast<Type>(Value); --用于基本类型间的转换,但不能用于基本类型指针间的转换: int i ...
- 【面试题】Java集合部分面试题
集合与数组? 数组:(可以存储基本数据类型)是用来存储对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用 集合:(只能存储对象,对象类型可以不一样)集合的长度可变,可在多数情况下使用 ...
- chsime.exe cpu占用高
打开管理员的命令提示符,运行 if exist "%SystemRoot%\System32\InputMethod\CHS\ChsIME.exe" (takeown /f &qu ...