进程和线程
本文为看雪论坛精华文章
看雪论坛作者ID:L0x1c
看了张银奎老师的书,记录一下。有很多比较官方的概念我直接抄了下来,所以不要喷我抄书,爱所有反卷局的大宝贝们!
1
进程资源
1、一个虚拟的地址空间,又被称为进程空间
2、全局唯一的进程ID,简称PID ( Client ID )
3、一个可执行映像,也是该进程的可执行文件在内存中的表示
4、一个或者多个线程
5、一个位于内核空间中的名为EPROCESS的数据结构,用来记录该进程的关键信息,包括进程的创建时间,映像文件名称等等
6、一个位于内核空间中的对象句柄表,用来记录和索引该进程所创建/打开的内核对象,操作系统根据该表格将用户模式下的句柄翻译为指向内核对象的指针
7、一个用于描述内存目录表起始位置的基地址,简称页目录基地址 ( DirBase ),当CPU切换到该任务/进程的时候,会将该地址加载到页表基地址寄存器CR3,这样当前进程的虚拟地址才会被翻译为正确的物理地址
8、一个位于用户空间中的进程环境块PEB
9、一个访问令牌,用于表示该进程的用户,安全组以及优先级
第一行代表了EPROCESS结构的地址 下面的三行代表了进程的关键的属性
CPU Meltdown和Spectry漏洞:
Meltdown
; rcx = kernel address
; rbx = probe_array
mov al, byte [rcx]
shl rax, 0xc
mov rbx, qword [rbx + rax]
NT内核中也引入了叫做KVA的补丁,会开启PCID的功能,查看一下KVA的模式为1,cr4的寄存器位17为1。
2
进程空间
访问模式
用户模式(user mode, 用户态) 内核模式( Kernel mode, 内核态)
使用INT 2E切换到内核模式:
_KiSystemService proc
ENTER_SYSCALL kss_a, kss_t ; set up trap frame and save state
?FpoValue = 0
;
; (eax) = Service number
; (edx) = Callers stack pointer
; (esi) = Current thread address
;
; All other registers have been saved and are free.
;
; Check if the service number within valid range
;
_KiSystemServiceRepeat:
mov edi, eax ; copy system service number
;edi = eax 等于了系统调用号
shr edi, SERVICE_TABLE_SHIFT ; isolate service table number
and edi, SERVICE_TABLE_MASK ;
; 这里用来确定是去找系统服务表还是驱动的表
mov ecx, edi ; save service table number
add edi, [esi]+ThServiceTable ; compute service descriptor address
; 指向系统服务表
mov ebx, eax ; save system service number
; ebx位系统调用号
and eax, SERVICE_NUMBER_MASK ; isolate service table offset
; eax为系统服务下标
;
; If the specified system service number is not within range, then attempt
; to convert the thread to a GUI thread and retry the service dispatch.
;
cmp eax, [edi]+SdLimit ; check if valid service
jae Kss_ErrorHandler ; if ae, try to convert to GUI thread
; 检查系统调用的下标是否超过了表的大小
;
; If the service is a GUI service and the GDI user batch queue is not empty,
; then call the appropriate service to flush the user batch.
;
cmp ecx, SERVICE_TABLE_TEST ; test if GUI service
; 跳转GUI API服务
jne short Kss40 ; if ne, not GUI service
mov ecx, PCR[PcTeb] ; get current thread TEB address
; ecx指向KPCR
xor ebx, ebx ; get number of batched GDI calls
KiSystemServiceAccessTeb:
or ebx, [ecx]+TbGdiBatchCount ; may cause an inpage exception
jz short Kss40 ; if z, no batched calls
push edx ; save address of user arguments
push eax ; save service number
call [_KeGdiFlushUserBatch] ; flush GDI user batch
pop eax ; restore service number
pop edx ; restore address of user arguments
;
; The arguments are passed on the stack. Therefore they always need to get
; copied since additional space has been allocated on the stack for the
; machine state frame. Note that we don't check for the zero argument case -
; copy is always done regardless of the number of arguments because the
; zero argument case is very rare.
;
Kss40: inc dword ptr PCR[PcPrcbData+PbSystemCalls] ; system calls
; 直接跳转到这里进行++系统调用数
FPOFRAME ?FpoValue, 0
mov esi, edx ; (esi)->User arguments
; 3环的指针
mov ebx, [edi]+SdNumber ; get argument table address
; 系统服务表
xor ecx, ecx
mov cl, byte ptr [ebx+eax] ; (ecx) = argument size
mov edi, [edi]+SdBase ; get service table address
mov ebx, [edi+eax*4] ; (ebx)-> service routine
; 指向的函数
sub esp, ecx ; allocate space for arguments
shr ecx, 2 ; (ecx) = number of argument DWORDs
mov edi, esp ; (es:edi)->location to receive 1st arg
cmp esi, _MmUserProbeAddress ; check if user address
jae kss80 ; if ae, then not user address
KiSystemServiceCopyArguments:
rep movsd ; copy the arguments to top of stack.
; Since we usually copy more than 3
; arguments. rep movsd is faster than
; mov instructions.
; 复制参数
;
; Make actual call to system service
;
kssdoit:
CAPSTARTX <_KiSystemService,ebx>
call ebx ; call system service
; call 系统服务
CAPENDX <_KiSystemService>
kss60:
快速系统调用
系统调用服务例程的地址放到寄存器中来避免读IDT这样的内存操作(??因为IDT 是INT xxx IDT表的东西),因为读寄存器的速度比读内存的速度要快很多 避免权限检查,也就是使用特殊的指令让CPU省去对系统服务调用来说根本不需要的权限检查
进行快速系统调用需要做的准备:
| ---------------- | ------- | -------------------- |
| SYSENTER_CS_MSR | 174 | 目标代码段的CS选择子 |
| SYSENTER_ESP_MSR | 175 | 目标ESP |
| SYSENTER_EIP_MSR | 176 | 目标EIP |
8053e540 b923000000 mov ecx,23h
8053e545 6a30 push 30h
8053e547 0fa1 pop fs
8053e549 8ed9 mov ds,cx
8053e54b 8ec1 mov es,cx
8053e54d 8b0d40f0dfff mov ecx,dword ptr ds:[0FFDFF040h]
8053e553 8b6104 mov esp,dword ptr [ecx+4]
8053e556 6a23 push 23h
KTRAP_FRAME 结构
开始逆!
kd> u nt!Kifastcallentry L20
nt!KiFastCallEntry:
8053e540 b923000000 mov ecx,23h
8053e545 6a30 push 30h
8053e547 0fa1 pop fs ;fs = 0x30
8053e549 8ed9 mov ds,cx ;ds = 0x23
8053e54b 8ec1 mov es,cx ;es = 0x23 都是段选择子有关的修改相应的权限的
8053e54d 8b0d40f0dfff mov ecx,dword ptr ds:[0FFDFF040h] ;ecx = _KTSS ptr
8053e553 8b6104 mov esp,dword ptr [ecx+4] ;esp = ESP0 -> KTRAP_FRAME的0x7c位置的V86Es
8053e556 6a23 push 23h ;_KTRAP_FRAME.HardwareSegSs = 0x23
8053e558 52 push edx ;_KTRAP_FRAME.HardwareEsp = edx (edx为三环的esp)
8053e559 9c pushfd ;_KTRAP_FRAME.EFlags = EFlags
8053e55a 6a02 push 2
8053e55c 83c208 add edx,8 ;因为edx为三环的esp,所以这个步骤是要去取三环的参数
8053e55f 9d popfd ;0环 EFlags = 0x2
8053e560 804c240102 or byte ptr [esp+1],2 ;EFlags的 IF位置1
8053e565 6a1b push 1Bh ;_KTRAP_FRAME.SegCs = 0x1B
8053e567 ff350403dfff push dword ptr ds:[0FFDF0304h] ;_KTRAP_FRAME.Eip为 kd> u 7c92e4f4 ntdll!KiFastSystemCallRet
8053e56d 6a00 push 0 ;_KTRAP_FRAME.ErrCode = 0
8053e56f 55 push ebp ;_KTRAP_FRAME.EBP = EBP
8053e570 53 push ebx ;_KTRAP_FRAME.EBX = EBX
8053e571 56 push esi ;_KTRAP_FRAME.ESI = ESI
8053e572 57 push edi ;_KTRAP_FRAME.EDI = EDI
8053e573 8b1d1cf0dfff mov ebx,dword ptr ds:[0FFDFF01Ch] ;ebx = _kpcr 0ffdff000
8053e579 6a3b push 3Bh ;_KTRAP_FRAME.SegFs = 0x3B
8053e57b 8bb324010000 mov esi,dword ptr [ebx+124h] ;esi = kpcr_kprcb_CurrentThread
8053e581 ff33 push dword ptr [ebx] ;_KTRAP_FRAME.ExceptionList = ExceptionList
8053e583 c703ffffffff mov dword ptr [ebx],0FFFFFFFFh ;ExceptionList = -1
8053e589 8b6e18 mov ebp,dword ptr [esi+18h] ;ebp = kpcr_kprcb_CurrentThread_InitialStack
8053e58c 6a01 push 1 ;_KTRAP_FRAME.PreviousPreviousMode = 1 代表三环过来的
8053e58e 83ec48 sub esp,48h ;esp = ntdll!_KTRAP_FRAME_ptr
8053e591 81ed9c020000 sub ebp,29Ch ;
8053e597 c6864001000001 mov byte ptr [esi+140h],1 ;kpcr_kprcb_CurrentThread_PreviousMode = 1 表示从3环调用来
8053e59e 3bec cmp ebp,esp ;比较当前的esp和ebp的位置
8053e5a0 759a jne nt!KiFastCallEntry2+0x47 (8053e53c) ;如果不相同则异常,正常都在_KTRAP_FRAME_ptr
8053e5a2 83652c00 and dword ptr [ebp+2Ch],0 ;_KTRAP_FRAME.Dr7 = 0
8053e5a6 f6462cff test byte ptr [esi+2Ch],0FFh ;DebugActive
8053e5aa 89ae34010000 mov dword ptr [esi+134h],ebp ;TrapFrame = ebp(_KTRAP_FRAME_ptr)
8053e5b0 0f854afeffff jne nt!Dr_FastCallDrSave (8053e400) ;检测是否被调试的状态
8053e5b6 8b5d60 mov ebx,dword ptr [ebp+60h] ;ebx = _KTRAP_FRAME.Ebp
8053e5b9 8b7d68 mov edi,dword ptr [ebp+68h] ;edi = _KTRAP_FRAME.Eip
8053e5bc 89550c mov dword ptr [ebp+0Ch],edx ;_KTRAP_FRAME.DbgArgPointer = edx 保存3环的参数指针
8053e5bf c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h ;_KTRAP_FRAME.DbgArgMark = 0BADB0D00h
8053e5c6 895d00 mov dword ptr [ebp],ebx ;_KTRAP_FRAME.DbgEbp = _KTRAP_FRAME.Ebp
8053e5c9 897d04 mov dword ptr [ebp+4],edi ;_KTRAP_FRAME.DbgEip = _KTRAP_FRAME.Eip
8053e5cc fb sti
8053e5cd 8bf8 mov edi,eax ;系统服务例程号
8053e5cf c1ef08 shr edi,8 ;右移八位
8053e5d2 83e730 and edi,30h ; index
8053e5d5 8bcf mov ecx,edi ; ecx = index
8053e5d7 03bee0000000 add edi,dword ptr [esi+0E0h] ;esi+0E0h = ServiceTable_ptr 代表是去找index=1还是=0的结构的项
8053e5dd 8bd8 mov ebx,eax ;系统服务例程号
8053e5df 25ff0f0000 and eax,0FFFh ;取后24位
8053e5e4 3b4708 cmp eax,dword ptr [edi+8] ;edi + 8的位置为MaxServiceNumber:最大的系统服务例程号
8053e5e7 0f8345fdffff jae nt!KiBBTUnexpectedRange (8053e332)
8053e5ed 83f910 cmp ecx,10h ;比较index是否为1
8053e5f0 751a jne nt!KiFastCallEntry+0xcc (8053e60c)
8053e5f2 8b0d18f0dfff mov ecx,dword ptr ds:[0FFDFF018h]
8053e5f8 33db xor ebx,ebx ;ebx = 0
8053e5fa 0b99700f0000 or ebx,dword ptr [ecx+0F70h] ;调试的时候发现这里都是0
8053e600 740a je nt!KiFastCallEntry+0xcc (8053e60c)
8053e602 52 push edx
8053e603 50 push eax
8053e604 ff15e43f5580 call dword ptr [nt!KeGdiFlushUserBatch (80553fe4)]
8053e60a 58 pop eax
8053e60b 5a pop edx
8053e60c ff0538f6dfff inc dword ptr ds:[0FFDFF638h] ;系统调用的次数+1
8053e612 8bf2 mov esi,edx ;三环的edx给了当前的esi
8053e614 8b5f0c mov ebx,dword ptr [edi+0Ch] ;ebx指向了参数表的
8053e617 33c9 xor ecx,ecx ;ecx = 0
8053e619 8a0c18 mov cl,byte ptr [eax+ebx] ;读取参数的个数ArgumentSizeTable:提供每个例程所需要的参数大小,这个值将要用来从 caller 里复制多少个参数
8053e61c 8b3f mov edi,dword ptr [edi] ;获取ServiceRoutineTable(提供真正的系统服务例程的地址)的地址
8053e61e 8b1c87 mov ebx,dword ptr [edi+eax*4] ;读取服务例程地址
8053e621 2be1 sub esp,ecx ;在当前栈上开辟空间容纳参数
8053e623 c1e902 shr ecx,2 ;ecx/4 获取参数个数
8053e626 8bfc mov edi,esp ;edi指向栈
8053e628 3b35d4995580 cmp esi,dword ptr [nt!MmUserProbeAddress (805599d4)] ;看是否属于用户空间
8053e62e 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (8053e7dc)
8053e634 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] ;复制参数到当前栈上
8053e636 ffd3 call ebx ;调用最终的服务例程
表示在windbg里面跟了一边 清晰多了!但是windbg太不好看了!决定换回windbg preview?
画一手流程图:
逆向调用
实例分析
3
线程
ETHREAD
TEB
4
WOW进程
架构:
工作过程
执行过程
00000000`754f271e 67448b0424 mov r8d,dword ptr [esp] ;取出32位的返回地址放到r8d因为到时候需要返回的时候需要
00000000`754f2723 458985bc000000 mov dword ptr [r13+0BCh],r8d ;可以看到r13是64位环境的栈底,保存了32位的返回地址
00000000`754f272a 4189a5c8000000 mov dword ptr [r13+0C8h],esp ;保存了32位的时候的栈帧
00000000`754f2731 498ba42480140000 mov rsp,qword ptr [r12+1480h] ;r12为teb的地址,这里取出了64位的rsp
00000000`754f2739 4983a4248014000000 and qword ptr [r12+1480h],0 ;清空缓存
00000000`754f2742 448bda mov r11d,edx ;r11d存放的是参数的地址
00000000`754f2745 41ff24cf jmp qword ptr [r15+rcx*8] ;跳转
注册表重定向
#include <windows.h>
#include <stdio.h>
int main()
{
//找到系统的启动项
char* Register = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
char* Myapp = "C:\\Users\\Administrator\\Desktop\\ctfmon.exe";
HKEY hKey;
//打开注册表启动项
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Register, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
{
RegSetValueExA(hKey, "Mytest", 0, REG_SZ, (BYTE*)Myapp, strlen(Myapp));
//关闭注册表
RegCloseKey(hKey);
printf("succeed!\n");
}
else
{
printf("Failed!");
return -1;
}
return 0;
}
注册表反射
5
创建进程
1、在父进程的用户空间中打开要执行的映像文件,确定其名称,类型和系统对它的设置选项
2、进入父进程的内核空间,为新进程创建EPROCESS结构,进程地址空间,KPROCESS结构和PEB
3、创建初始线程,但是创建的时候指定了挂起标志,并不会立刻开始运行
4、通知子系统服务程序,对于windows程序,通知windows子系统服务进程CSRSS
5、初始线程开始在内核空间执行
6、通过APC的方式,在新进程自己的空间中执行初始化动作,主要是通过NTDLL.DLL中的加载器,加载进程所依赖的DLL文件
6
最小进程和Pico进程
看雪ID:L0x1c
https://bbs.pediy.com/user-home-873515.htm
官网:https://www.bagevent.com/event/6334937
# 往期推荐
1.All About Crypto - CTF竞赛密码学方向指南
6. CVE-2012-3569 VMware OVF Tool格式化字符串漏洞分析
球分享
球点赞
球在看
点击“阅读原文”,了解更多!