- 博客(94)
- 收藏
- 关注
原创 x64遍历VAD
#include <ntifs.h>typedef struct _MMADDRESS_NODE{ ULONG64 u1; struct _MMADDRESS_NODE* LeftChild; struct _MMADDRESS_NODE* RightChild; ULONG64 StartingVpn; ULONG64 EndingVpn;}MMADDRESS_NOD...
2018-12-18 22:17:56
1763
3
原创 2.内核回调机制
有谁调用了窗口过程?GetMessage()在处理SentMessagesListHead中消息时DispatchMessage(&msg)在处理其他队列中的消息时CreateWindow() 0环的一些代码也会调用窗口过程,但它没有发消息给队列而是直接调用窗口过程(KeUserModeCallback)NtUserCreateWindowEx()这样设计是因为,如果你程序需要...
2018-11-07 19:38:03
2262
原创 1.消息机制
typedef struct _Color{ DWORD r,g,b;}Color;typedef struct _WindowClass{ DWORD x; DWORD y; DWORD width; DWORD hight; Color color;}WindowClass;//画窗口void PaintWindows(HDC hdc,WindowClass* W...
2018-11-06 15:34:59
694
1
原创 3.缺页异常
P: 当前页面是否有效当CPU访问一个地址,其PTE的P位为0,此时会产生缺页异常缺页异常Windows每一秒都在发生,Windows使用缺页异常可以更加有效的使用这个物理页。比如你当前有效的物理内存只有2M,在某个地方被使用了就会一直被占用,必须要它释放我们才能用,这样的话效率是非常低的。Windows是只有正在被使用的线性地址才会给你挂上物理页,如果你的线性地址隔了一段时间没使用或者...
2018-11-06 10:15:41
1373
原创 2.物理内存的管理
物理内存最大物理内存10-10-12分页 最多识别物理内存为4GB2-9-9-12分页 最多识别物理内存为64GB操作系统的 _ExVerifySuite() 函数限制了它无法超越4GB(网上有补丁可以突破4GB)实际物理内存MmNumberOfPhysicalPages * 4 = 物理内存一共有7FF6C个物理页,乘4后得到的就是 KB。物理内存管理全局数组数...
2018-11-05 21:44:05
744
原创 1.线性地址的管理
进程空间的地址划分线性地址有4G 但未必都能访问,所以需要记录,哪些地方分配了比如你申请了一块内存在0x12345678的位置大小为4字节,这些都要被记录总不能在这申请了下次还在这申请在_EPROCESS.+ 0x11c VadRoot 这是一颗搜索二叉树,它里面的没一个节点都记录了一块被占用的线性地址空间。VadRoot的类型为_MMVADkd&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; dt _MMVA
2018-11-05 10:02:58
767
原创 7. SEH + 硬件断点HOOK
DLL#include<windows.h>#include <TlHelp32.h>#include <stdio.h>#include <limits.h>typedef HANDLE(WINAPI *OPENTHREAD) (DWORD dwFlag, BOOL bUnknow, DWORD dwThreadId);OPENTHR...
2018-11-04 20:34:37
2377
1
原创 6.硬件断点
调试寄存器DR0~DR3:调试地址寄存器,用于设置硬件断点DR4~DR5:保留,未公开具体作用DR6:调试寄存器组状态寄存器DR7:调试寄存器组控制寄存器硬件断点的原理是使用DR0~DR3设置地址,使用DR7设置状态,因此最多设置4个。&amp;amp;lt;1&amp;amp;gt; L0/G0 ~ L3/G3: L0/G0对应DR0,L1/G1对应DR1,以此类推…,用于控制Dr0~Dr3是否有效,Lx是局...
2018-11-04 15:34:13
3018
原创 5.内存断点
原理就是对所设地址的属性设置为不可读不可写属性,这样当这个地址被访问或写入就会产生异常。//改变内存地址内存页的属性BOOL VirtualProtectEx( IN HANDLE hProcess,// 要修改内存的进程句柄 IN LPVOID lpAddress,// 要修改内存的起始地址 IN SIZE_T dwSize,// 页区域大小 IN DWORD flNewPr...
2018-11-03 21:53:22
591
原创 4.软件断点
调试的本质:想办法让被调试程序触发异常触发异常后就会向DEBUG_OBJECT里发送调试事件调试器接管异常的过程一般调试器都会有软件断点,内存断点,硬件断点… 其实这些无非就是想让被调试程序触发异常再让调试器来接管。在OD中随便一个地址按下F2后程序执行到那就会被断下来,这时调试器将会拥有被调试程序的控制权,这个过程我们称为“中断到调试器”。当我们在OD中按下F2其实就是将那个地...
2018-11-03 17:36:34
1919
原创 3.调试事件的处理
调试器会有一个循环一直判断EventList有没有调试事件有就取出来处理。调试器创建形式关联调试器与被调试器进程调试循环每一种收集调试事件API都不一样,是因为它要收集调试事件的类型是不一样的。这是异常要收集的调试事件typedef struct _EXCEPTION_DEBUG_INFO { EXCEPTION_RECORD ExceptionRecord; ...
2018-11-02 15:50:42
1027
原创 2.调试事件的采集
typedef struct _DEBUG_OBJECT{ KEVENT EventsPresent; FAST_MUTEX Mutex; LIST_ENTRY EventList; union { ULONG Flags; struct { UCHAR DebuggerInacti...
2018-11-02 09:25:49
552
原创 1.调试对象
将一个程序拖拽进OD中,这种方式是通过 CreateProcess() 建立联系的。程序正在运行中通过OD附加程序,这种方式是通过 DebugActiveProcess() 建立联系的。DebugActiveProcess执行流程&amp;lt;1&amp;gt; kernel32! DbaUiConnectToDbg()ntdll! DbgUiConnectToDbg()ntdll! ZwC...
2018-11-01 19:57:30
1024
1
原创 7.未处理异常
当异常发生的处理流程:CPU检测到异常查IDT表执行中断处理程序CommonDispatchExceptior(CxxThrowException RaiseException RtIRaiseException() NtRaiseException KiRaiseException)KiDispatchExceptionKiUserExceptionDispatcherRtIDispa...
2018-11-01 09:34:32
1146
原创 6.编译器拓展SEH
//1.挂入链表相当于这部分//fs[0]-&amp;amp;gt; Exception _asm { mov eax, fs:[0] mov temp,eax lea ecx,Exception mov fs:[0],ecx } //为SEH成员赋值 Exception.Next = (_EXCEPTION*)temp; Exception.Handler = (DWORD)&amp;amp;am...
2018-10-31 20:26:45
498
原创 5.SEH(结构化异常处理)
当用户异常产生后,内核函数KiDispatchException并不是像处理内核异常那样在0环直接进行处理,而是修正3环EIP为KiUserExceptionDispatcher函数后就结束了。这样,当线程再次回到3环时,将会从KiUserExceptionDispatcher函数开始执行。KiUserExceptionDispatcher会调用RtIDispatchException函数来查...
2018-10-30 20:08:27
1178
原创 4.VEH(向量化异常处理)
当用户异常产生后,内核函数KiDispatchException并不是像处理内核异常那样在0环直接进行处理,而是修正3环EIP为KiUserExceptionDispatcher函数后就结束了。这样,当线程再次回到3环时,将会从KiUserExceptionDispatcher函数开始执行。(ntdll.dll) KiUserExceptionDispatcher函数分析调用 RtIDis...
2018-10-30 12:53:31
6890
原创 3.用户异常的分发
异常如果发生在内核层,处理起来比较简单,因为异常处理函数也在0环,不用切换堆栈,但是如果异常发生在3环,就意味着必须要切换堆栈,回到3环执行处理函数。切换堆栈的处理方式与用户APC的执行过程几乎是一样的,唯一的区别就是执行用户APC时返回3环后执行的函数是KiUserApcDispatcher,而异常处理时返回3环后执行的函数是KiUserExceptionDispatcher.所以,理解用户...
2018-10-29 21:36:17
687
原创 2.内核异常处理流程
用户层异常与内核层异常异常可以发生在用户空间,也可以发生在内核空间。无论是CPU异常还是模拟异常,是用户层异常还是内核异常,都要通过 KiDispatchException函数进行分发,这个函数比较复杂。VOID KiDispatchException( ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, First...
2018-10-29 16:18:41
1440
原创 1.异常记录
我们主要围绕这个主线展开:异常记录异常分发异常处理异常的分类CPU产生的异常软件模拟产生的常这种属于CPU产生的异常int main(){ int a = 10; int b = 0; int val = a / b;}这种属于软件模拟的异常void a(){ throw 1;}int main(){ a();}CPU异常产生过程CPU...
2018-10-29 09:47:16
475
原创 2.全局句柄表
所有的进程和线程无论无论是否打开,都在这个表中。每个进程和线程都有一个唯一的编号: PID和CID 这两个值其实就是全局句柄表中的索引。进程和线程的查询,主要是以下三个函数,按照给定的PID或CID从PspCidTable从查找相应的进线程对象:PsLookupProcessThreadByCid()PsLookupProcessByProcessld()PsLookupThread...
2018-10-28 22:22:49
554
1
原创 1.句柄表
什么是句柄(内核对象)当一个进程创建或者打开一个内核对象时,将获得一个句柄,通过这个句柄可以访问内核对象。如:HANDLE g_hMutex =::CreateMutex(NULL,FALSE, &amp;amp;quot;XYZ&amp;amp;quot;);HANDLE g_hMutex =::OpenMutex(MUTEX ALL ACCESS, FALSE, &amp;amp;quot;XYZ&amp;amp;quot;
2018-10-28 21:17:35
363
原创 7.互斥体
为什么要有互斥体:等待对象被遗弃互斥体(MUTANT)与事件(EVENT)和信号量(SEMAPHORE)一样,都可以用来·进行线程的同步控制。但需要指出的是,这几个对象都是内核对象,这就意味着,通过这些对象可以进行跨进程的线程同步控制,比如:A进程中的X线程与B进程中的Y线程,它们可以共同使用一个内核对象来进行线程同步控制。极端情况:如果B进程的Y线程还没有来得及调用修改SignalS...
2018-10-28 13:33:20
1741
原创 6.信号量
事件(EVENT)对象,线程在进入临界区之前会通过调用 WaitForSingleObject或者WaitForMultipleObjects来判断当前的事件对象是否有信号 (SignalState>0),只有当事件对象有信号时,才可以进入临界区(只允许一个线程进入直到退出的一段代码,不单指用EnterCriticalSection()和LeaveCriticalSection()而形成的临...
2018-10-27 20:21:25
321
原创 5.事件
在之前的课程里面讲过,线程在进入临界区之前会调用WaitForSingleObject或者WaitForMultipleOobjects,此时如果有信号,线程会从函数中退出并进入临界区,如果没有信号那么线程将自己挂入等待链表,然后将自己挂入等待网,最后切换线程。其他线程在适当的时候,调用方法修改被等待对象的 SignalState 为有信号(不同的等待对象,会调用不同的函数),并将等待该对象的其...
2018-10-27 14:12:39
214
原创 4.WaitForSingleObject函数分析
无论可等待对象是何种类型,线程都是通过:WaitForSingleObjectWaitForMultipleObjects进入等待状态的,这两个函数是理解线程等待与唤醒进制的核心WaitForSingleObject参数说明WaitForSingleObject对应的内核函数:NTSTATUS stdcall NtWaitForSingleObject( HANDLE Handl...
2018-10-26 19:27:55
801
原创 3.线程等待与唤醒
我们在之前的讲解了如何自己实现临界区以及什么是Windows自旋锁,这两种同步方案在线程无法进入临界区时都会让当前线程进入等待状态,一种是通过Sleep函数实现的,一种是通过让当前的CPU&amp;amp;quot;空转”实现的,但这两种等待方式都有局限性:通过Sleep函数进行等待,等待时间该如何确定呢?通过“空转”的方式进行等待,只有等待时间很短的情况下才有意义,否则对CPU资源是种浪费。而且自旋锁只能在多核的环...
2018-10-26 09:42:53
701
原创 2.自旋锁
1、不同版本的内核文件单核:2-9-9-12分页 ntkrnlpa.exe10-10-12分页 ntoskrnl.exe多核:2-9-9-12分页 ntkrnlpa.exe10-10-12分页 ntoskrnl.exe文件虽然相同但单核与多核的代码是不一样的,自旋锁只有在多核下才是有价值的。Windows自旋锁参考: KeAcquireSpinLockAtDpcLevel多核...
2018-10-25 22:26:59
260
原创 1.临界区
并发是指多个线程在同时执行:单核–(是分时执行,不是真正的同时)多核–(在某一个时刻,会同时有多个线程再执行)同步则是保证在并发执行的环境中各个线程可以有序的执行分析两条线程执行下面代码。DWORD dwVal =0; //全局变量线程中的代码:dwVal ++; //只有一行安全吗?对应的汇编代码:mov eax,[0x12345678] add eax,1 mov ...
2018-10-25 17:12:10
413
原创 5.用户APC执行过程
当产生系统调用、中断或者异常,线程在返回用户空间前都会调用, _KiServiceExit函数,在_KiServiceExit会判断是否有要执行的用户APC,如果有则调用KiDeliverApc函数(第一个参数为1)进行处理。执行用户APC时的堆栈操作处理用户APC要比内核APC复杂的多,因为,用户APC函数要在用户空间执行的,这里涉及到大量换栈的操作:当线程从用户层进入内核层时,要保留原来...
2018-10-25 09:55:58
1761
2
原创 4.内核APC执行过程
APC函数的执行与插入并不是同一个线程:在A线程中向B线程插入一个APC,插入的动作是在A线程中完成的,但什么时候执行则由B线程决定!,所以叫“异步过程调用&quot;内核APC函数与用户APC函数的执行时间和执行方式也有区别,我们本节课主要学习内核APC的执行过程。执行点1:线程切换SwapContext //判断是否有内核APCKiSwapThreadKiDelicerApc /...
2018-10-24 16:16:11
1788
原创 3.APC的挂入过程
无论是正常状态还是挂靠状态,都有两个APC队列,一个内核队列,一个用户队列。每当要挂入一个APC函数时,不管是内核APC还是用户APC,内核都要准备一个KAPC的数据结构,并且将这个KAPC结构挂到相应的APC队列中。kd&amp;amp;gt; dt _kapcnt!_KAPC +0x000 Type //类型APC类型为0x12 +0x002 Size //本结构体的大小0x30...
2018-10-23 22:01:09
658
原创 2.备用APC队列
如果想让线程做什么事情,就给它的APC队列里面挂一个APC。kd&gt; dt _kthreadnt!_KTHREAD...+0x034 ApcState : _KAPC_STATE//APC...+0x138 ApcStatePointer : [2] Ptr32 _KAPC_STATE//APC指针...+0x14c SavedApcState : _K...
2018-10-23 12:18:04
329
原创 1.APC机制
线程是不能被“杀掉”、“挂起”、“恢复”的,线程在执行的时候自己占据着CPU,别人怎么可能控制它呢?举个极端的例子:如果不调用API,屏蔽中断,并保证代码不出现异常,线程将永久占用CPU,何谈控制呢?所以说线程如果想“死&amp;amp;quot;,一定是自己执行代码把自己杀死,不存在“他杀”这种情况!那如果想改变一个线程的行为该怎么办呢?可以给他提供一个函数,让它自己去调用,这个函数就是APC (Asyncrone...
2018-10-22 22:51:50
430
原创 13.跨进程读写内存
跨进程的本质是"进程挂靠”正常情况下, A进程的线程只能访问A进程的地址空间,如果A进程的线程想访问B进程的地址空间,就要修改当前的Cr3的值为B进程的页目录表基值(KPROCESS.DirectoryTableBase)。即: mov cr3,B.DirectoryTableBase跨进程操作A进制中的线程代码:mov cr3,B.DirectoryTableBase //切换Cr3...
2018-10-22 20:49:40
3902
1
原创 12.进程挂靠
进程与线程的关系:一个逃程可以包含多个线程一个进程至少要有一个线程进程为线程提供资源,也就是提供Cr3的值, Cr3中存储的是页目录表基址, Cr3确定了,线程能访问的内存也就确定了。进程与线程的关系线程代码:mov eax, dword ptr ds:(0x12345678]CPU如何解析0x12345678这个地址呢?CPU解析线性地址时要通过页目录表来找对应的物理页,页目录...
2018-10-22 15:50:41
877
1
原创 11.Windows线程切换_线程优先级
(1)、当前线程主动调用API:API函数->KiSwapThread->KiSwapContext->SwapContexti(2)、当前线程时间片到期:KiDispatchInterrupt->KiQuantumEnd->SwapContext(3)、有备用线程(KPCR.PrcbData.NextThread)KiDispatchInterrupt-&...
2018-10-22 06:36:08
1446
原创 10.Windows线程切换_FS段寄存器
FS:[0]寄存器在3环时指向TEB.进入0环后FS:[0]指向KPCR系统中同时存在很多个线程,这就意味着FS:[0]在3环时指向的TEB要有多个(每个线程一份)。但在实际的使用中我们发现,当我们在3环查看不同线程的FS寄存器时, FS的段选择子都是相同的,那是如何实现通过一个FS寄存器指向多个TEB呢?下面是ida的分析代码 ; CODE ...
2018-10-21 08:23:01
501
1
原创 9.Windows线程切换_TSS
SwapContext这个函数是Windows线程切换的核心,无论是主动切换还,是系统时钟导致的线程切换,最终都会调用这个函数。在这个函数中除了切换堆栈以外,还做了很多其他的事情,了解这些细节对我们学习操作系统至关重要。下面我们看看线程切换与TSS的关系。栈底开始往上0x210个字节存储浮点寄存器的值,以上都是TrapFrame结构(在api3环进0环已经讲过了)。调用API进0环普...
2018-10-20 22:55:30
1253
原创 8.Windows线程切换_时间片管理
时钟中断会导致线程进行切换,但并不是说只要有时钟中断就一定会切换线程,时钟中断时,两种情况会导致线程切换:当前的线程CPU时间片到期有备用线程(KPCR.PrcbData.NextThread)关于CPU时间片当一个新的线程开始执行时,初始化程序会在KTHREAD.Quantum赋初始值,该值的大小由KPROCESS.ThreadQuantum决定(观察ThreadQuantum大小...
2018-10-20 16:45:09
3376
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人