系统调用篇-开篇
前言
为了更好的学习内核驱动,我们先将驱动篇暂缓,先来了解一下什么系统调用过程,本篇将带你初步了解一下系统api的调用过程(初步,后续会更加详细的介绍和解释)。
01/
API函数调用过程举例:ReadProcessMemory
.text
:7C8021D0
mov
edi
,
edi
.text
:7C8021D2
push
ebp
.text
:7C8021D3
mov
ebp
,
esp
.text
:7C8021D5
lea
eax
,
[ebp+BufferLength]
.text
:7C8021D8
push
eax
;
ReturnLength
.text
:7C8021D9
push
[ebp+BufferLength]
;
BufferLength
.text
:7C8021DC
push
[ebp+Buffer]
;
Buffer
.text
:7C8021DF
push
[ebp+BaseAddress]
;
BaseAddress
.text
:7C8021E2
push
[ebp+ProcessHandle]
;
ProcessHandle
.text
:7C8021E5
call
ds
:NtReadVirtualMemory
.text
:7C8021EB
mov
ecx
,
[ebp+lpNumberOfBytesRead]
.text
:7C8021EE
test
ecx
,
ecx
.text
:7C8021F0
jnz
short
loc_7C8021FD
.text
:7C8021F2
.text
:7C8021F2
loc_7C8021F2
: ;
CODE
XREF
:
ReadProcessMemory
+32
j
.text
:7C8021F2
test
eax
,
eax
.text
:7C8021F4
jl
short
loc_7C802204
.text
:7C8021F6
xor
eax
,
eax
.text
:7C8021F8
inc
eax
.text
:7C8021F9
.text
:7C8021F9
loc_7C8021F9
: ;
CODE
XREF
:
ReadProcessMemory
+3
C
j
.text
:7C8021F9
pop
ebp
.text
:7C8021FA
retn
14
h
.text
:7C8021FD
;
---------------------------------------------------------------------------
.text
:7C8021FD
.text
:7C8021FD
loc_7C8021FD
: ;
CODE
XREF
:
ReadProcessMemory
+20
j
.text
:7C8021FD
mov
edx
,
[ebp+BufferLength]
.text
:7C802200
mov
[ecx]
,
edx
.text
:7C802202
jmp
short
loc_7C8021F2
.text
:7C802204
;
---------------------------------------------------------------------------
.text
:7C802204
.text
:7C802204
loc_7C802204
: ;
CODE
XREF
:
ReadProcessMemory
+24
j
.text
:7C802204
push
eax
;
NtStatus
.text
:7C802205
call
sub_7C8093FD
.text
:7C80220A
xor
eax
,
eax
.text
:7C80220C
jmp
short
loc_7C8021F9
-
一些没用的,比如提升堆栈、保留现场等,就不分析了,直接分析关键点:
BOOL
ReadProcessMemory
(
HANDLE hProcess,
// 目标进程的句柄
LPCVOID lpBaseAddress,
// 要读取的内存的起始地址
LPVOID lpBuffer,
// 存储读取数据的缓冲区
SIZE_T nSize,
// 要读取的字节数
SIZE_T *lpNumberOfBytesRead
// 读取的实际字节数
)
;
ReadProcessMemory
函数有五个参数,参数传递如下:
ReadProcessMemory
函数内部调用了一个ds:NtReadVirtualMemory
,而该函数属于:ntdll。
- 当调用完毕
ds:NtReadVirtualMemory
函数后,eax存储的就是该函数返回值,接着进行判断,该返回值是否小于0,如果小于0则跳转
- 跳转地址如下:
跳转后,会将ds:NtReadVirtualMemory
函数返回值eax,传递给sub_7C8093FD
该处地址,我们跟进去看
- 发现该函数只调用了一个函数:
那么我们来仔细分析一下ds:NtReadVirtualMemory
函数。因为该函数位于ntdll中
02/
ntdll!NtReadVirtualMemory
- 我们可以看到
NtReadVirtualMemor
mov
eax, 0BBh ; 0BBh代表真正操作系统内核中某一个函数的编号
mov
edx, 7FFE0300h ;7FFE0300h存了一个函数,该函数决定了我们用什么方式进入0环
call
dword ptr [edx]
retn
4
以上,只是提供了一个进入0环的方式,然后在0环中如何执行,又以什么方式进入0环等问题。我们后面会详细讲解。
03/
课后作业:自己编写WriteProcessMemory函数(不使用任何DLL)
先看WriteProcessMemory的结构
BOOL
WriteProcessMemory(
HANDLE
hProcess,
LPVOID
lpBaseAddress,
LPCVOID
lpBuffer,
SIZE_T
nSize,
SIZE_T
*lpNumberOfBytesWritten
);
参数说明:
- hProcess:目标进程的句柄,即要写入数据的进程。
- lpBaseAddress:要写入数据的起始地址。
- lpBuffer:包含要写入目标进程的数据的缓冲区
- nSize:要写入的字节数
- lpNumberOfBytesWritten:一个指向变量的指针,用于接收实际写入的字节
先直接给大家看代码,然后在分析流程:
// 重写WriteProcessMemory.cpp : Defines the entry point for the console application.
//
BOOL __declspec(naked) _
stdcall
WriteProcessMemory0
( HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesWritten)
{
_asm
{
mov eax,
115
h;
mov edx,
7F
FE0300h;
call dword ptr [edx];
retn
14
h;
}
}
int
main
(
int
argc,
char
* argv[])
{
int
i =
0
;
printf
(
"WriteProcessMemory0 begin: i = %xn"
,i);
int
buffer =
0x1234
;
SIZE_T lpNumberOfBytesWritten;
BOOL ret = WriteProcessMemory0((HANDLE)GetCurrentProcess(),&i,&buffer,
sizeof
(
int
),
NULL
);
printf
(
"WriteProcessMemory0 end: i = %xn"
,i);
getchar();
return
0
;
}
我们已经把i的地址给重写了。
流程分析
原文始发于微信公众号(loochSec):系统调用-API函数调用过程
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论