系统调用
持续更新...
分析OpenProcess函数
我们在三环写一个OpenProcess来跟踪调试一下
#include <windows.h>
int main()
{
__asm {
mov eax, 0x100;
}
OpenProcess(NULL, NULL, NULL);
return 0;
}
这里的mov eax, 0x100;
是为了让我们快速定位,直接od附加搜索指令即可追踪到当前点。然后我们来看一下OpenProcess是怎么调用的。
这里首先走到了kernel32.OpenProcess,然后步入继续跟踪
接下来到了KernelBase.OpenProcess
继续走进去,发现到了ntdll.NtOpenProcess
然后call了一个0x7FFE0300
接着就是sysenter的快速调用指令,从这里执行后返回直接到了kernelbase
比如我们的ReadProcessMemory,他也是这么走下来的。
随着迭代式开发越来越迅速,在kernel32中实现的函数功能已经满足不了了。
我们老的Xp系统是没有KernelBase的,到了Win7就有了KernelBase了,在XP下走的是Kernel32,如果升级了Win7,那么之前xp下的程序还是需要可以正常使用的。
但是Win7做了很多的改造,所以还是调用Kernel32,但是他不去实现很多功能了,而是直接跳到KernelBase。
举个例子:
比如在XP下的OpenProcess有三个参数,升级了Win7之后有四个参数,如果修改了Kernel32,那么原来XP的在Win7上是不是就不兼容了
因为不能修改,所以就做个跳板,jmp kernelbase,增加一个默认参数。这样win7也能走,xp也不会有问题。
我们用IDA分析一下win7 32位的kernel32
可以看到这里只有一个jmp
我们去导入表看一下
这个东西只是一个跳板
本质上来说他什么事情都没有干
所以根据刚才的分析,我们是应该去看一下kernelbase的。
在KernelBase中依然可以看到是三个参数。
我们来看一下他在干什么
那么里面的ClientId是什么呢?我们去结构体窗口看一下
如果是进程就填到UniqueProcess
,如果是线程就填到UniqueThread
下面还有一个ObjectAttributes
,由于我们打开进程是通过进程ID打开的,不是通过名字,所以这个结构的初始化全都是0。
再接着往下就调用了NtOpenProcess
就变成了四个参数,其实这个KernelBase.OpenProcess本质上就是把参数整理了一下,填充了一下额外参数去调用NtOpenProcess
,然后判断一下返回值是不是0,经过判断,如果小于0就跳转到GetLastError
将内核错误码转换到三环错误码。
我们去ntdll中找NtOpenProcess
这里发现没有找到,我们去看导出表
发现导出的名字和真正的名字是不一样的,真正的名字叫ZwOpenProcess
,也就是一个函数导出了两个名字
我们看到了一行这样的汇编指令:mov edx, 7FFE0300h
,然后下面就call了这个地址,这是什么意思呢?这是个结构,所有的进程都有这个地址。这个结构所有进程共享。
windbg:dt _KUSER_SHARED_DATA
nt!_KUSER_SHARED_DATA
+0x000 TickCountLowDeprecated : Uint4B
+0x004 TickCountMultiplier : Uint4B
+0x008 InterruptTime : _KSYSTEM_TIME
+0x014 SystemTime : _KSYSTEM_TIME
+0x020 TimeZoneBias : _KSYSTEM_TIME
+0x02c ImageNumberLow : Uint2B
+0x02e ImageNumberHigh : Uint2B
+0x030 NtSystemRoot : [260] Wchar
+0x238 MaxStackTraceDepth : Uint4B
+0x23c CryptoExponent : Uint4B
+0x240 TimeZoneId : Uint4B
+0x244 LargePageMinimum : Uint4B
+0x248 Reserved2 : [7] Uint4B
+0x264 NtProductType : _NT_PRODUCT_TYPE
+0x268 ProductTypeIsValid : UChar
+0x26c NtMajorVersion : Uint4B
+0x270 NtMinorVersion : Uint4B
+0x274 ProcessorFeatures : [64] UChar
+0x2b4 Reserved1 : Uint4B
+0x2b8 Reserved3 : Uint4B
+0x2bc TimeSlip : Uint4B
+0x2c0 AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE
+0x2c4 AltArchitecturePad : [1] Uint4B
+0x2c8 SystemExpirationDate : _LARGE_INTEGER
+0x2d0 SuiteMask : Uint4B
+0x2d4 KdDebuggerEnabled : UChar
+0x2d5 NXSupportPolicy : UChar
+0x2d8 ActiveConsoleId : Uint4B
+0x2dc DismountCount : Uint4B
+0x2e0 ComPlusPackage : Uint4B
+0x2e4 LastSystemRITEventTickCount : Uint4B
+0x2e8 NumberOfPhysicalPages : Uint4B
+0x2ec SafeBootMode : UChar
+0x2ed TscQpcData : UChar
+0x2ed TscQpcEnabled : Pos 0, 1 Bit
+0x2ed TscQpcSpareFlag : Pos 1, 1 Bit
+0x2ed TscQpcShift : Pos 2, 6 Bits
+0x2ee TscQpcPad : [2] UChar
+0x2f0 SharedDataFlags : Uint4B
+0x2f0 DbgErrorPortPresent : Pos 0, 1 Bit
+0x2f0 DbgElevationEnabled : Pos 1, 1 Bit
+0x2f0 DbgVirtEnabled : Pos 2, 1 Bit
+0x2f0 DbgInstallerDetectEnabled : Pos 3, 1 Bit
+0x2f0 DbgSystemDllRelocated : Pos 4, 1 Bit
+0x2f0 DbgDynProcessorEnabled : Pos 5, 1 Bit
+0x2f0 DbgSEHValidationEnabled : Pos 6, 1 Bit
+0x2f0 SpareBits : Pos 7, 25 Bits
+0x2f4 DataFlagsPad : [1] Uint4B
+0x2f8 TestRetInstruction : Uint8B
+0x300 SystemCall : Uint4B
+0x304 SystemCallReturn : Uint4B
+0x308 SystemCallPad : [3] Uint8B
+0x320 TickCount : _KSYSTEM_TIME
+0x320 TickCountQuad : Uint8B
+0x320 ReservedTickCountOverlay : [3] Uint4B
+0x32c TickCountPad : [1] Uint4B
+0x330 Cookie : Uint4B
+0x334 CookiePad : [1] Uint4B
+0x338 ConsoleSessionForegroundProcessId : Int8B
+0x340 Wow64SharedInformation : [16] Uint4B
+0x380 UserModeGlobalLogger : [16] Uint2B
+0x3a0 ImageFileExecutionOptions : Uint4B
+0x3a4 LangGenerationCount : Uint4B
+0x3a8 Reserved5 : Uint8B
+0x3b0 InterruptTimeBias : Uint8B
+0x3b8 TscQpcBias : Uint8B
+0x3c0 ActiveProcessorCount : Uint4B
+0x3c4 ActiveGroupCount : Uint2B
+0x3c6 Reserved4 : Uint2B
+0x3c8 AitSamplingValue : Uint4B
+0x3cc AppCompatFlag : Uint4B
+0x3d0 SystemDllNativeRelocation : Uint8B
+0x3d8 SystemDllWowRelocation : Uint4B
+0x3dc XStatePad : [1] Uint4B
+0x3e0 XState : _XSTATE_CONFIGURATION
这个结构不是300这个值,而是:7FFE0000
,所以我们来:dt _KUSER_SHARED_DATA 7FFE0000
nt!_KUSER_SHARED_DATA
+0x000 TickCountLowDeprecated : 0
+0x004 TickCountMultiplier : 0xf99a027
+0x008 InterruptTime : _KSYSTEM_TIME
+0x014 SystemTime : _KSYSTEM_TIME
+0x020 TimeZoneBias : _KSYSTEM_TIME
+0x02c ImageNumberLow : 0x14c
+0x02e ImageNumberHigh : 0x14c
+0x030 NtSystemRoot : [260] "C:\Windows"
+0x238 MaxStackTraceDepth : 0
+0x23c CryptoExponent : 0
+0x240 TimeZoneId : 0
+0x244 LargePageMinimum : 0x200000
+0x248 Reserved2 : [7] 0
+0x264 NtProductType : 1 ( NtProductWinNt )
+0x268 ProductTypeIsValid : 0x1 ''
+0x26c NtMajorVersion : 6
+0x270 NtMinorVersion : 1
+0x274 ProcessorFeatures : [64] ""
+0x2b4 Reserved1 : 0x7ffeffff
+0x2b8 Reserved3 : 0x80000000
+0x2bc TimeSlip : 0
+0x2c0 AlternativeArchitecture : 0 ( StandardDesign )
+0x2c4 AltArchitecturePad : [1] 0
+0x2c8 SystemExpirationDate : _LARGE_INTEGER 0x0
+0x2d0 SuiteMask : 0x110
+0x2d4 KdDebuggerEnabled : 0x3 ''
+0x2d5 NXSupportPolicy : 0x2 ''
+0x2d8 ActiveConsoleId : 1
+0x2dc DismountCount : 0
+0x2e0 ComPlusPackage : 0xffffffff
+0x2e4 LastSystemRITEventTickCount : 0x53db7e4
+0x2e8 NumberOfPhysicalPages : 0x7ff7e
+0x2ec SafeBootMode : 0 ''
+0x2ed TscQpcData : 0 ''
+0x2ed TscQpcEnabled : 0y0
+0x2ed TscQpcSpareFlag : 0y0
+0x2ed TscQpcShift : 0y000000 (0)
+0x2ee TscQpcPad : [2] ""
+0x2f0 SharedDataFlags : 0xe
+0x2f0 DbgErrorPortPresent : 0y0
+0x2f0 DbgElevationEnabled : 0y1
+0x2f0 DbgVirtEnabled : 0y1
+0x2f0 DbgInstallerDetectEnabled : 0y1
+0x2f0 DbgSystemDllRelocated : 0y0
+0x2f0 DbgDynProcessorEnabled : 0y0
+0x2f0 DbgSEHValidationEnabled : 0y0
+0x2f0 SpareBits : 0y0000000000000000000000000 (0)
+0x2f4 DataFlagsPad : [1] 0
+0x2f8 TestRetInstruction : 0xc3
+0x300 SystemCall : 0x772570b0
+0x304 SystemCallReturn : 0x772570b4
+0x308 SystemCallPad : [3] 0
+0x320 TickCount : _KSYSTEM_TIME
+0x320 TickCountQuad : 0x574d81
+0x320 ReservedTickCountOverlay : [3] 0x574d81
+0x32c TickCountPad : [1] 0
+0x330 Cookie : 0x89ed980a
+0x334 CookiePad : [1] 0
+0x338 ConsoleSessionForegroundProcessId : 0n3064
+0x340 Wow64SharedInformation : [16] 0
+0x380 UserModeGlobalLogger : [16] 0
+0x3a0 ImageFileExecutionOptions : 0
+0x3a4 LangGenerationCount : 1
+0x3a8 Reserved5 : 0
+0x3b0 InterruptTimeBias : 0
+0x3b8 TscQpcBias : 0
+0x3c0 ActiveProcessorCount : 4
+0x3c4 ActiveGroupCount : 1
+0x3c6 Reserved4 : 0
+0x3c8 AitSamplingValue : 0
+0x3cc AppCompatFlag : 1
+0x3d0 SystemDllNativeRelocation : 0xff350000
+0x3d8 SystemDllWowRelocation : 0
+0x3dc XStatePad : [1] 0
+0x3e0 XState : _XSTATE_CONFIGURATION
我们在这个结构偏移300的位置找到了这个成员: +0x300 SystemCall : 0x772570b0
,这是个函数叫SystemCall。
这个结构是所有进程共享的,也就是共享同一份物理地址,我们去看看内核的这个结构体,地址是:FFDF0000
可以看到和三环是同一个地址
但是我们在直接用u 0x772570b0
看不到这个内存,因为system进程没有模块,看不到,所以我们去附加一个进程去看
我们去reload一下符号再看
也就是说这里调用的是KiFastSystemCall
,
我们再看一下这个地方:mov eax, 0BEh
这个BE是服务号
我们去ntdll看一下这个函数
这里把esp给了edx,这个esp是什么?
从上一个函数call过来的时候,esp就是上个函数的返回地址,然后进行sysenter
,他带参数进内核了吗?这里看起来好像是没带参数。
这里就会有疑问:
- 怎么带参数进内核?
- 参数有多少个?
- 他需要如何返回?
- sysenter如何进内核?
自己实现OpenProcess
#include "stdafx.h"
#include <iostream>
#include <windows.h>
typedef struct _CLIENT_ID
{
DWORD UniqueProcess;
DWORD UniqueThread;
}CLIENT_ID, *PCLIENT_ID;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
NTSTATUS __stdcall MyZwOpenProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId
);
HANDLE MyOpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
)
{
CLIENT_ID ClientID;
OBJECT_ATTRIBUTES ObjectAttributes;
ClientID.UniqueProcess = dwProcessId;
if (bInheritHandle == TRUE)
{
ObjectAttributes.Attributes = 2;
}
else
{
ObjectAttributes.Attributes = 0;
}
ClientID.UniqueThread = 0;
ObjectAttributes.Length = 0x18;
ObjectAttributes.RootDirectory = 0;
ObjectAttributes.ObjectName = 0;
ObjectAttributes.SecurityDescriptor = 0;
ObjectAttributes.SecurityQualityOfService = 0;
DWORD dwRet = MyZwOpenProcess((PHANDLE)&dwProcessId, dwDesiredAccess,
&ObjectAttributes, &ClientID);
if (dwRet < 0)
{
//BaseSetLastNTError(dwRet);//设置错误码
return 0;
}
return (HANDLE)dwProcessId;//这里是返回句柄
}
__declspec(naked) NTSTATUS __stdcall MyZwOpenProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId
)
{
__asm
{
mov eax, 0BEh
mov edx, 7FFE0300h
call dword ptr[edx]
ret 10h
}
}
int main()
{
HANDLE hProcess = MyOpenProcess(PROCESS_ALL_ACCESS, FALSE, 3740);
if (!hProcess)
{
return 0;
}
printf("ProcessHandle is:%x\r\n ", hProcess);
getchar();
}