逆向RING0程序从这里

ring0下使用内核重载绕过杀软hook 内核重载听起来是一个很高大上的概念,但其实跟PE的知识息息相关,那么为什么会有内核重载的出现呢? 我们知道从ring3进入ring0需要通过int2e/sysenter(syscall)进入ring0,而进入ring0之后又会通过KiFastCallEntry/KiSystemService去找SSDT表对应响应的内核函数,那么杀软会在这两个地方进行重点盯防。 首先是对int2e/sysenter的盯防,我们知道大多数函数都是通过一系列的调用链,最终找到ntdll.dll里面的函数,找到调用号后通过int 阅读详情
接触RING 0之前,以为得学很多东西,一大堆驱动开发的知识。不过后来想了想,驱动壳等其他不直接访问硬件的程序为了兼容性,不可能真的直接访问硬件,也就是那些是基于硬件抽象层之上的,而且大部分使用的还是系统提供的API(RING0下使用的API称为NATIVE API)。事情一下子变简单了,除非你想通过逆向硬件厂商驱动,自己编写优化硬件或者超频程序。
虽然这是纯静态分析,但是我希望通过分析整个驱动,你会理解一些RING0下的机制,并且懂得在动态调试中应该如何下断点定位代码。
在开始之前,感谢rockhard的源代码和已编译好的驱动,这样我就可以不必学习WINDDK的使用了。你可以在下面链接的附件中得到:
http://bbs.pediy.com/showthread.php?s=&threadid=35626
初步实现系统级拦截应用程序取硬盘物理序列号
Rockhard发表上述文章时的目标是通过简单修改REGMON驱动部分的源代码完成拦截应用程序取硬盘物理序列号的功能,难免有不足之处。个人对源代码的不成熟评论并不针对Rockhard。
学习逆向时,我的方法是先看看高级语言代码编译后究竟是怎么样的。或许最后我还是得学习WINDDK的使用,编写代码,编译,反汇编,它会解答一些疑问。下面让我来以源码和反汇编代码对照的形式来说明RING0下的一些机制。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
DriverEntry,驱动程序的入口函数,驱动的一些初始化操作,将在这里进行。象RING3那样,程序通过堆栈访问DriverObject和RegistryPath。而在IDA,反汇编后是这样子:“; int __stdcall start(PDRIVER_OBJECT DriverObject,HANDLE Handle)”第二个参数的名字有点不同,不过不重要,我们知道,其实它是一样的。
.text:000105A0                 push    7
.text:000105A2                 pop     ecx
.text:000105A3                 mov     esi, offset s_DeviceHdhook ; "[url=file://device//HDHOOK]//Device//HDHOOK[/url]"
.text:000105A8                 lea     edi, [ebp+regnameNt]
.text:000105AE                 push    9
.text:000105B0                 rep movsd
.text:000105B2                 movsw
.text:000105B4                 pop     ecx
.text:000105B5                 mov     esi, offset s_DosdevicesHdh ; "[url=file://dosdevices//HDHOOK]//DosDevices//HDHOOK[/url]"
.text:000105BA                 lea     edi, [ebp+regnameDos]
.text:000105C0                 push    206B6444h       ; Tag
.text:000105C5                 rep movsd
.text:000105C7                 movsw
.text:000105C9                 mov     esi, offset s_Start ; "Start"
.text:000105CE                 lea     edi, [ebp+SourceString]
.text:000105D1                 movsd
.text:000105D2                 movsd
.text:000105D3                 movsd
.text:000105D4                 mov     esi, [ebp+Handle]
.text:000105D7                 movzx   eax, word ptr [esi]
.text:000105DA                 inc     eax
.text:000105DB                 inc     eax
.text:000105DC                 push    eax             ; NumberOfBytes
.text:000105DD                 push    1               ; PoolType
.text:000105DF                 call    ds:ExAllocatePoolWithTag
前面一大堆代码,都是因为下面3个局部变量的定义,编译器会生成一段代码,先将这些字符移进堆栈,然后再使用。
WCHAR                   deviceNameBuffer[]  = L"[url=file://device//%22DRIVER_NAME]//Device//"DRIVER_NAME[/url];
WCHAR                   deviceLinkBuffer[]  = L"[url=file://dosdevices//%22DRIVER_NAME]//DosDevices//"DRIVER_NAME[/url];
WCHAR                   startValueBuffer[] = L"Start";
从逆向的角度来看,象这种静态字符变量,如果换成全局变量,或者可以获得更高的运行效率和更小的程序。值得注意的是NATIVE API的调用,第一个参数入栈后的几行代码,仍然是局部变量的初始化,这编译器让我想起扭曲变形的介绍。000105D4的代码是从堆栈中取得DriverEntry的第二参数,它是一个UNICODE_STRING结构,从MSDN中搜索到的说明(如无特别说明,一切资料都是从MSDN中搜索得到):
typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING *PUNICODE_STRING;
从000105D7处的代码来看,该结构在反汇编是:
  WORD  Length
  WORD  MaximumLength
  DWORD  Buffer(指向字符的指针)
通过逆向RtlInitUnicodeString,可知上述结构中的 MaximumLength成员,其实就相当于Length + sizeof(UNICODE_NULL)。关于调用ExAllocatePoolWithTag的第三参数PoolType:
typedef enum _POOL_TYPE {
  NonPagedPool,
  PagedPool,
  NonPagedPoolMustSucceed,
  DontUseThisType,
  NonPagedPoolCacheAligned,
  PagedPoolCacheAligned,
  NonPagedPoolCacheAlignedMustS
} POOL_TYPE;
这里看起来跟PUSH 1好象没有什么关系,现在看看源代码:
    registryPath.Buffer = ExAllocatePool( PagedPool,
                                          RegistryPath->Length + sizeof(UNICODE_NULL));
这里使用的参数是PagedPool,对于enum类型的定义,每个成员代表的数字是从0开始递增。PagedPool刚好在第二个位置,所以它是1。源代码使用的ExAllocatePool,反汇编后的代码使用的是ExAllocatePoolWithTag。MSDN的说法是ExAllocatePool已经被舍弃了,取代的是ExAllocatePoolWithTag(以标识申请内存)。调用API之后是对返回结果的判断:
    if (!registryPath.Buffer) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
它对应的汇编代码是
.text:000105E5                 mov     edi, eax
.text:000105E7                 xor     ebx, ebx
.text:000105E9                 cmp     edi, ebx
.text:000105EB                 mov     [ebp+Path], edi
.text:000105EE                 jnz     short loc_105FA
.text:000105EE
.text:000105F0                 mov     eax, 0C000009Ah
.text:000105F5                 jmp     loc_1075A
注意到000105F0,STATUS_INSUFFICIENT_RESOURCES=0C000009Ah,仍然使用EAX作为返回参数。接下来的源代码,终于看到编译优化了:
    registryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
    registryPath.MaximumLength = registryPath.Length;
    RtlZeroMemory( registryPath.Buffer, registryPath.Length );
    RtlMoveMemory( registryPath.Buffer,  RegistryPath->Buffer,
                   RegistryPath->Length  );
    RtlZeroMemory( &paramTable[0], sizeof(paramTable));
这里本来要调用2个API的。对于前一个RtlZeroMemory调用,编译器使用自己的代码来代替它:
.text:000105FA                 mov     ax, [esi]
.text:000105FD                 add     ax, 2
.text:00010601                 movzx   ecx, ax
.text:00010604                 mov     edx, ecx
.text:00010606                 xor     eax, eax
.text:00010608                 shr     ecx, 2
.text:0001060B                 rep stosd
.text:0001060D                 mov     ecx, edx
.text:0001060F                 and     ecx, 3
.text:00010612                 rep stosb
先是4字节对齐的填0,然后使用AND取得除以4后的余数,继续填0。第二次调用,编译器同样使用自己的代码来实现这个功能:
.text:00010624                 add     esp, 0Ch
.text:00010627                 xor     eax, eax
.text:00010629                 lea     edi, [ebp+QueryTable]
.text:0001062F                 push    0Eh
.text:00010631                 pop     ecx
.text:00010632                 rep stosd
现在让我们再来看看系统中RtlZeroMemory的代码:
00402520: 57                       PUSH EDI
00402521: 8B7C2408                 MOV EDI, [ESP+08]
00402525: 8B4C240C                 MOV ECX, [ESP+0C]
00402529: 33C0                     XOR EAX, EAX
0040252B: FC                       CLD ;这一句用来保证DF=0
0040252C: 8BD1                     MOV EDX, ECX
0040252E: 83E203                   AND EDX, 00000003
00402531: C1E902                   SHR ECX, 02
00402534: F3AB                     REP STOSD  
00402536: 0BCA                     OR ECX, EDX
00402538: 7504                     JNZ 40253E;非4字节对齐,继续填0
0040253A: 5F                       POP EDI
0040253B: C20800                   RETN 0008
0040253E: F3AA                     REP STOSB  
00402540: 5F                       POP EDI
00402541: C20800                   RETN 0008

高级语言似乎不提供修改标志寄存器的功能,CLD可以省掉。在编译过程中比较需要填0的内存是否4字节对齐,把比较语句也省了。这里的代码没有以函数的形式出现,当然连传递参数和保存环境的代码也省了。至于RtlMoveMemory,编译器用下面代码代替:
.text:00010614                 movzx   eax, word ptr [esi]
.text:00010617                 push    eax             ; size_t
.text:00010618                 push    dword ptr [esi+4] ; void *
.text:0001061B                 push    [ebp+Path]      ; void *
.text:0001061E                 call    ds:memmove
选择使用MEMMOVE而不是RtlMoveMemory。简单分析了一下,前者为每种情况都准备了一个独立的处理例程,通过跳转表的形式来实现,后者则是使用了不少比较命令。由于代码量较多,有兴趣的可以自己看看。
编译出来的程序,至少在代码段,看起来跟RING 3没有什么区别,同样可以通过程序实现的功能和驱动导入表,估计程序用了什么API,下断,并最终定位目标功能代码。我们需要做的事,只是熟悉这些API和一些常用的RING0机制,然后就可以象分析RING 3程序一样分析RING 0了。下面我将把重点放在API的解释。程序下一个调用的API是RtlQueryRegistryValues,MSDN可以查得该函数的功能是访问注册表。其中一个参数的结构如下:
typedef struct _RTL_QUERY_REGISTRY_TABLE {
    PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
    ULONG Flags;
    PWSTR Name;
    PVOID EntryContext;
    ULONG DefaultType;
    PVOID DefaultData;
    ULONG DefaultLength;
} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
关于Flags标记,可用的常量如下:
RTL_QUERY_REGISTRY_SUBKEY  
RTL_QUERY_REGISTRY_TOPKEY  
RTL_QUERY_REGISTRY_REQUIRED  
RTL_QUERY_REGISTRY_NOVALUE  
RTL_QUERY_REGISTRY_NOEXPAND  
RTL_QUERY_REGISTRY_DIRECT  
RTL_QUERY_REGISTRY_DELETE
对于这类型常量定义,从1(二进制)开始,第二个是10(二进制),第三个是100(二进制),如此类推。源代码中使用的是RTL_QUERY_REGISTRY_DIRECT,所以有如下代码:
.text:0001064F                 mov     [ebp+QueryTable.Flags], 20h
这里有点想不明白,在此API调用之前的大段代码和几个API的调用,都是为了初始化此API的Path参数。为什么不能直接使用入口参数RegistryPath的BUFFER,而要另外分配内存,转移 数据 在作为传入参数?另外在此API的注释中看到这一句话“The table must be allocated from nonpaged pool.”。程序没有申请一块nonpaged内存存放QueryTable结构,而是直接使用堆栈。难道RING 0下的堆栈都是nonpaged的?此外程序此后并没有对该API的返回值或者返回 数据 作任何处理。这里大胆假设一下到目前为止的代码都是垃圾代码。另外我注意到编译器的对于每行代码几乎都是很机械的编译,下面源代码:
    paramTable[0].EntryContext = &startType;
    paramTable[0].DefaultType = REG_DWORD;
    paramTable[0].DefaultData = &startType;
对应的反汇编代码:
.text:00010634                 lea     eax, [ebp+var_4]
.text:00010637                 push    4
.text:00010639                 mov     [ebp+QueryTable.EntryContext], eax
.text:0001063C                 lea     eax, [ebp+var_4]
.text:0001063F                 pop     edi
.text:00010640                 mov     [ebp+QueryTable.DefaultData], eax
编译器将相同的赋值语句归类了,但是却对EAX重复赋值,显然0001063C处的代码可以省略。接下来是ZwOpenKey。根据NTSTATUS的定义(详见WINDDK中的ntstatus.h),最高位有如下定义:
//          00 – Success      ;对应的16进制最高位0
//          01 – Informational    ;4
//          10 – Warning      ;8
//          11 – Error        ;c
比较是否成功调用的代码是:
.text:0001069D                 test    eax, eax
.text:0001069F                 jl      short loc_106CF;最高位为1(调用失败),跳
在RING 3下API调用失败返回的是-1,NATIVE API则是以返回值的最高位来判断调用是否成功。
.text:00010675                 lea     eax, [ebp+Handle]
.text:00010678                 push    20006h          ; DesiredAccess
.text:0001067D                 push    eax             ; KeyHandle
.text:0001067E                 mov     [ebp+ObjectAttributes.RootDirectory], ebx
.text:00010681                 mov     [ebp+ObjectAttributes.Attributes], 40h
.text:00010688                 mov     [ebp+ObjectAttributes.ObjectName], esi
.text:0001068B                 mov     [ebp+ObjectAttributes.SecurityDescriptor], ebx
.text:0001068E                 mov     [ebp+ObjectAttributes.SecurityQualityOfService], ebx
.text:00010691                 call    ds:ZwOpenKey
由上面代码可知,该API的KeyHandle参数,使用的就是DriverEntry的第二个参数。也就是说KeyHandle其实就是一个UNICODE_STRING结构。搞不懂micro$oft,一样的东西搞这么多概念干什么。另外想不明白的是,假如该API调用成功,将会在注册表写入一些 数据 。但是对程序的运行没有影响。ZwOpenKey调用失败了反而省了几行代码。随后是IoCreateDevice和IoCreateSymbolicLink建立驱动对象和符号连接,API调用失败则把建立的对象和符号连接删除。为IRP_MJ_SHUTDOWN,IRP_MJ_CREATE,IRP_MJ_CLOSE和IRP_MJ_DEVICE_CONTROL分派处理例程。分别有下面对应关系:
       名称                                    描述                            调用的API
IRP_MJ_CREATE                       请求一个句柄                           CreateFile  
IRP_MJ_CLOSE                       关闭句柄                             CloseHandle  
IRP_MJ_DEVICE_CONTROL        控制操作(利用IOCTL宏)        DeviceIoControl  
IRP_MJ_SHUTDOWN                   系统关闭                                InitiateSystemShutdown
当RING 3程序调用上述API对驱动进行操作时,系统会查找该IRP对应的处理例程地址,并调用该例程。
.text:0001071B                 mov     eax, offset sub_104B4
.text:00010720                 cmp     edi, ebx
.text:00010722                 mov     [esi+70h], eax
.text:00010725                 mov     [esi+40h], eax
.text:00010728                 mov     [esi+38h], eax
.text:0001072B                 mov     [esi+78h], eax
此处ESI指向的是DriverEntry的第一个参数DriverObject。+38h是IRP_MJ_CREATE,+40h是IRP_MJ_CLOSE。具体请查阅WINDDK中的wdm.h。
.text:0001074E                 mov     eax, ds:KeServiceDescriptorTable
.text:00010753                 mov     dword_1080C, eax
执行完这两行代码,把SSDT存到全局变量中便结束了DriverEntry例程,也就是说驱动的初始化完毕了。实现驱动功能的代码在IRP例程中,这让我想起RING 3下的消息环。下面来看看sub_104B4:
.text:000104B4 sub_104B4       proc near               ; DATA XREF: start+187 o
.text:000104B4                  ;按照IRPDispatch例程的定义
.text:000104B4 arg_0           = dword ptr  8      ;DeviceObject
.text:000104B4 arg_4           = dword ptr  0Ch    ;pIrp
关于pIrp结构,MSDN中的定义不完整。对照源代码可知:
+0ch    DWORD    AssociatedIrp.SystemBuffer
+18h    DWORD    IoStatus.Status
+1Ch    DWORD    IoStatus.Information
+3ch    DWORD    UserBuffer
+60h    DWORD    irpStack
irpStack:
+00h    BYTE    MajorFunction ,查询WINDDK中的WDM.h可知
#define IRP_MJ_CREATE                      0x00
#define IRP_MJ_CLOSE                      0x02
#define IRP_MJ_DEVICE_CONTROL           0x0e
#define IRP_MJ_SHUTDOWN                 0x10
+04h    DWORD    Parameters.DeviceIoControl.OutputBufferLength
+08h    DWORD    Parameters.DeviceIoControl.InputBufferLength
+0ch    DWORD    Parameters.DeviceIoControl.IoControlCode
+18h    DWORD    FileObject
该函数根据不同的IRP消息,进入不同的流程。其中从IRP_MJ_DEVICE_CONTROL的处理流程可知,当IoControlCode的低3位为111(二进制,即METHOD_NEITHER)时,驱动程序使用UserBuffer返回 数据 ,反之则使用SystemBuffer。现在来看看sub_103DA,即是源代码中的HDHookDeviceControl函数:
.text:000103EB                 cmp     ecx, 83050000h
.text:000103F1                 jz      loc_104A7
.text:000103F1
.text:000103F7                 cmp     ecx, 83050004h
.text:000103FD                 jz      loc_104A0
.text:000103FD
.text:00010403                 cmp     ecx, 83050008h
.text:00010409                 jz      short loc_1047E
.text:00010409
.text:0001040B                 cmp     ecx, 8305000Ch
.text:00010411                 jz      short loc_10452
.text:00010411
.text:00010413                 cmp     ecx, 83050010h
.text:00010419                 jz      short loc_10426
函数将IoControlCode保存在ECX中,经过对比跳转到相关代码中。在用户态程序中,通过下面API与驱动进行通信:
BOOL DeviceIoControl(
    HANDLE hDevice,  // handle to device of interest
    DWORD dwIoControlCode,  // control code of operation to perform
    LPVOID lpInBuffer,  // pointer to buffer to supply input data
    DWORD nInBufferSize,  // size of input buffer
    LPVOID lpOutBuffer,  // pointer to buffer to receive output data
    DWORD nOutBufferSize,  // size of output buffer
    LPDWORD lpBytesReturned,  // pointer to variable to receive output byte count
    LPOVERLAPPED lpOverlapped   // pointer to overlapped structure for asynchronous operation
   );
也就是说,拦截该API,取得dwIoControlCode,在IRP分派例程的入口下条件断点。然后便可以定位驱动中相关的功能代码。我想看到这里,大家都大概了解RING 0的一些机制,并且能尝试动态调试一些程序了。该程序大部分代码的功能Rockhard在他的贴里已经讲得很清楚了,除了如何取得系统调用号。我们知道系统调用号随着系统版本,甚至SP之间也会有所不同,如何兼容各版本?我对此很感兴趣,先看看源代码:
VOID HookStart( void )
{
    if( !IsHooked ) {
        RealZwDeviceIoControlFile = SYSCALL( ZwDeviceIoControlFile );
        SYSCALL( ZwDeviceIoControlFile ) = (PVOID) HookZwDeviceIoControlFile;
        IsHooked = TRUE;
    }
}
你能想象这样的代码能取得ZwDeviceIoControlFile在SSDT中的位置吗?现在再让我们看看反汇编代码:
.text:00010381                 mov     eax, ds:ZwDeviceIoControlFile
.text:00010386                 mov     ecx, ssdt
.text:0001038C                 push    esi
.text:0001038D                 mov     edx, [eax+1];这里有点奇怪,取函数的机械码?
.text:00010390                 mov     esi, [ecx]
.text:00010392                 mov     edx, [esi+edx*4]
.text:00010395                 pop     esi
.text:00010396                 mov     dword_10814, edx
.text:0001039C                 mov     eax, [eax+1]
.text:0001039F                 mov     ecx, [ecx]
.text:000103A1                 mov     dword ptr [ecx+eax*4], offset sub_1030E
现在让我们来看看ZwDeviceIoControlFile的代码:
00400BC6: B838000000               MOV EAX, 00000038
00400BCB: 8D542404                 LEA EDX, [ESP+04]
00400BCF: CD2E                     INT 2E
00400BD1: C22800                   RETN 0028
入口点加1,便是系统调用号。最后感谢所有看到这里的人  
Ring3触发BSOD代码实现及内核逆向分析 0、引言 做过Windows内核开发或者驱动开发的朋友,必然常常会遇到BSoD,其全称为Blue Screen of Death;of作为介词,其缩写o则需要小写了;然而Windows NT内核当时推出时,想必微软也大势宣传其是进程安全的,不像DOS那样,一个进程挂了,整个系统就挂了;当然,如果对于系统启动过程非常熟悉的话,应该听说过一些系统的关键进程如csrss.exe挂了的话,则整个系统必然挂;这篇文章的目的就是揭露这后边的秘密,看看系统是如何选择性死亡了,这也牵扯到另一桩生意——一些恶意代码就喜欢鱼 阅读详情

相关推荐

用户层下API的逆向分析及重构

Windows所提供给R3环的API,实质就是对操作系统接口的封装,其实现部分都是在R0实现的。很多恶意程序会利用钩子来钩取这些API,从而达到截取内容,修改数据的意图。现在我们使用ollydbg对ReadProcessMemory进行跟踪分析,查看其在R3的实现。 测试 od 我们首先在od里面跟一下在ring3层ReadProcessMemory的调用过程 首先在 exe 中 调用 kernel32.ReadProcessMemory函数,我们可以看到这一部分主要是call dword ptr ds:

hongduilanjun的博客 1189

逆向RING0程序从这里开始

标 题: 逆向RING0程序从这里开始作 者: 笨笨雄时 间: 2006-12-06,21:41链 接: http://bbs.pediy.com/showthread.php?threadid=35999【文章标题】: 逆向RING0程序从这里开始【文章作者】: 笨笨雄【作者邮箱】: nemo314@gmail.com【使用工具】: IDA接触RING 0之前,以为得学很多东西,一大堆驱动开发的

晓斌的博客 994

2、逆向分析KiFastCallEntry

sysenter指令做了那些事情 在 Ring3 的代码调用了 sysenter 指令之后,CPU 会做出如下的操作: 1. 将 SYSENTER_CS_MSR 的值装载到 cs 寄存器 174 2. 将 SYSENTER_EIP_MSR 的值装载到 eip 寄存器 176 3. 将 SYSENTER_CS_MSR 的值加 8(Ring0 的堆栈段描述符)装载到 ss 寄存器。 4. 将 SYSENTER_ESP_MSR 的值装载到 esp 寄存器 175 5. 将特权级切换到 Ring0 6. 如果

Windows内核学习笔记 458

DeviceIoControl

若这个参数为0,则对象将以独占的方式打开。(通常serial port 是以这种方式)CreateFiledwShareMode If this parameter is 0 (zero) and CreateFile succeeds, the object cannot be shared and cannot be opened again until the handle is close

WhyGoSoFar的专栏 2323

使用DeviceIoControl进行通信(直接方式)

一个WDM驱动,然后caller使用DeviceIoControl进行和驱动的通信。输出buffer使用METHOD_IN_DIRECT进行数据传输。

hook更改硬盘序列号 转载

在驱动层hook ZwDeviceIoControlFile,当有请求获取硬盘物理SN时,返回指定SN,从而达到模拟硬盘物理SN的效果. 本工具包含源码,可自行编译.

Hook 内核函数技术细节

刚开始看到通过 SSDT 来 HOOK ZwXXX 内核函数的方法时不是很了解, 等把 ZwXXX 反汇编后才发现技术细节.原来也没什么新鲜的,就是找到目标函数在 SSDT 中的位置( 偏移量=位置*4 ), 然后保存并替换偏移量处的值为自己新的函数地址就行了。 这种技术现在已是老掉牙了,不过在实际的软件开发中也比较常用, 可以实现各种监控功能.上次安了个诺顿, 它把所有的 ZwXXX 都给

FISH 的专栏 4078

DeviceIoControl、CreateFile,结合WMI读取物理硬盘网卡mac特征码,完整源码工程实例

DeviceIoControl() CreateFile() 读取硬件物理网卡mac完整工程实例 Vs2012 c++ 源代码 功能:结合WMI和DeviceIoControl获取网卡原生MAC地址和当前MAC地址 入口参数: iQueryType:需要获取的网卡类型 0:包括USB网卡 1:不包括USB网卡 pMacAddress:存储网卡MAC地址 uSize:可存储的最大网卡数目 返回值: -1:不支持的设备属性值 -2:WMI连接失败

对A盾原理的小小总结,膜拜A神

A盾的原理是在驱动加载时重载os内核,获取原始ssdt表的地址。 应用层点击查询的代码在文件A-ProtectView.cpp中,每种点击操作调用相应的 query查询函数,在query函数里ReadFile。读操作的Handle是A盾自定义的操作码, 类似DeviceIoControl的控制码,比如handle为LIST_SSDT,LIST_INLINEHOOK等。 驱动加载...

weixin_33704591的博客 347

HDHook(附源码)HookAPI改变硬盘串号和MAC地址

VC++源码 一个使用detours来HookAPI的简单例子 DeviceIoControl获取硬盘串号 GetAdaptersInfo获取MAC Hook这两个API改变获取的硬盘串号和MAC地址 HDHook工程 生成dll GetHDDSN工程 载入生成的dll 获取硬盘串号和MAC地址 需要自行安装detours

diskhook模拟硬盘物理序列号

模拟硬盘物理序列号,一般软件的注册码都和它有关

使用NtUserBuildHwndList遍历窗口_win7x64

在我的上一篇文章中讲到 http://blog.youkuaiyun.com/zhuhuibeishadiao/article/details/51604788 枚举窗口 使用EnumWinodws是调用内核中NtUserBuildHwndList 这个函数最后2个参数必须是R3的地址 不然会返回0xC0000008错误,并且如果使用控制台窗口测试,这时ETHREAD下的win32Thr

zhuhuibeishadiao 6479

Abaqus小白必看:用Micromechanics Plugin轻松搞定RVE周期性边界条件(附避坑指南)

本文为Abaqus初学者提供了使用官方Micromechanics Plugin插件高效实现复合材料代表性体积单元分析的完整指南。文章详细讲解了从插件安装、模型准备、周期性边界条件自动设置到结果验证的全流程,并重点分享了处理复杂模型和避免常见错误的实用技巧,帮助用户大幅提升RVE分析效率与准确性。

weixin_28363123的博客 802

逆向ring0msg

by 执着一生 最近抽空把ring0msg[相关文章请参阅“邪恶的RING0注射ShellCode脆弱的PE加载机制”作者:hellfish]给逆了下,其实也不是什么高深的技术,很早的时候老外就搞出来了,只不过带ring3层的操作而已,稍微改改就完全可以用一个sys搞定。    原理也不复杂,其实就是修改线程入口点改变流程,让线程开始的时候先执行shellcode而已。ThreadCont

1073

Windows 10下用VS2022编译AFSIM 2.9.0的完整避坑指南

本文提供了在Windows 10系统下,使用Visual Studio 2022编译AFSIM 2.9.0仿真框架的详细指南。文章系统梳理了从环境准备、CMake配置、编译链接到安装打包的全流程,并重点针对编译过程中常见的文件编码、命名空间冲突等高频错误提供了具体解决方案,旨在帮助开发者高效避坑,顺利完成AFSIM在Windows平台上的构建。

weixin_28839549的博客 550

AI人工智能与TensorFlow的教育科技应用

随着科技的飞速发展,AI人工智能在各个领域都展现出了巨大的潜力,教育领域也不例外。本文章的目的在于深入探讨AI人工智能与TensorFlow在教育科技中的具体应用,包括智能教学系统的开发、学生学习情况的评估与预测等方面。范围涵盖了从基础概念到实际项目应用的各个层面,旨在为教育科技工作者和相关研究者提供全面且深入的技术指导。本文将首先介绍AI人工智能和TensorFlow的核心概念及其联系,让读者对相关技术有基本的了解。接着详细讲解核心算法原理和具体操作步骤,并结合数学模型和公式进行深入分析。

AI智能探索者的博客 1699

逆向RING0工程

接触RING 0之前,以为得学很多东西,一大堆驱动开发的知识。不过后来想了想,驱动壳等其他不直接访问硬件的程序为了兼容性,不可能真的直接访问硬件,也就是那些是基于硬件抽象层之上的,而且大部分使用的还是系统提供的API(RING0下使用的API称为NATIVE API)。事情一下子变简单了,除非你想通过逆向硬件厂商驱动,自己编写优化硬件或者超频程序。虽然这是纯静态分析,但是我希望通过分析整个驱动,你

CharlesPrince的专栏 1612

初识YUV,实战NV21格式数据转换为Bitmap

初识YUV,并使用YUV数据生成Bitmap图像一、初识YUV二、采样方式2.1、YUV 4:4:42.2、YUV 4:2:22.2、YUV 4:2:2 一、初识YUV 说到YUV我们就必须先从RGB说起了,如下图所示,请各位把每个色块当成一个像素点。通常一个像素点由RGB(Alpha我们先不考虑)三原色组成。 如下图中第一个像素点,其RGB值分别为(236,102,93),而这三个值就组成了我们看到的 红色 。 然而上图中除了RGB值外,我还标出了每个像素点的YUV的值,YUV的值是怎么来的呢?直接给公

乐翁龙 7127

RING3到RING0

当我在说跳转时,说的什么? CPU有很多指令,不是所有的指令都能够随时用,比如 ltr指令就不是随便什么时候能用,在保护模式下,如果你不安规则来执行指令,CPU就会抛出异常,比如你在INTEL手册上就能看到如下文本 意思据是说,如果你当前的CPL不是RING0,那么就会抛出GP(0)异常! 所以要正确使用这个指令,你就需要将CPL跳转到RING0来。这就是跳转! RING3到RI...

weixin_30632089的博客 183

本地大模型部署实战:LM Studio与Ollama的易用性与性能深度评测

本文对两款主流本地大模型部署工具LM Studio和Ollama进行了深度评测。LM Studio凭借图形化界面和内置模型库,为新手提供了开箱即用的便捷体验,并支持OpenAI兼容API,易于生态集成。Ollama则以命令行驱动,轻量高效,凭借其原生API和Modelfile自定义能力,在自动化集成和性能方面表现突出。文章从易用性、模型生态、性能及扩展性多维度对比,帮助用户根据自身技术背景和使用场景做出最佳选择。

weixin_29039773的博客 529

堆一呼一吸之间:动态扩缩容引发JVM堆内存震荡的伸缩算法、代际传导与容器定容解析

Kubernetes扩容后,新Java实例的GC频率常比老实例高出数倍,堆容量反复伸缩。本文从一次支付系统的GC陡增出发,结合HotSpot源码与JDK 8实测,拆解堆伸缩的记账规则:期望容量以GC后已用量为基数、以Xms为下限,按空闲比例判断扩缩,收缩只在老年代回收后按0%、10%、40%、100%步进;再剖析年轻代随老年代联动、晋升风暴与元空间触发线,对比Parallel、G1、ZGC等收集器及JDK 26的变化,讨论容器分账、HPA共振与原地扩缩容,最后给出分级定容、预热与监控的方案。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 15万+

【梅哥的Ring0湿润插入教程】【番外篇四】抓取盛大GPK驱动保护文件及简略逆向...

【梅哥的Ring0湿润插入教程】Email:mlkui@163.com 转载请注明出处,谢绝喷子记者等,如引起各类不适请自觉滚J8蛋!番外篇四:抓取盛大GPK驱动保护文件及简略逆向【湿润前言】 随着驱动保护技术的逐步成熟,诸如网络游戏公司等越来越多的商业软件公司开始使用Ring0级保护技术保护自己的产品,以起到反用户级调试、反RootKit、反各类钩子、反各类远程注入等作用。...

aejtu5698的博客 5358

手把手教你完成基于matlab的LSTM时间序列分析

时间序列是按时间顺序组织的数字序列,是数据分析中重要的处理对象之一。时间序列的主要特点是数据获取方式一般具有客观性,能反映某种现象的变化趋势或统计指标,进而预测未来走向,这在本质上也是一个回归预测的问题。长短时记忆网络(Long Short-Term Memory,LSTM)是一种循环神经网络,适合处理有更长时间跨度的内部记忆,被广泛应用于时间序列分析,能够保持数据的内在持续性,反映数据的细粒度走势,具有良好的预测效果。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 897

Hook技术(1):Hook技术简介

什么是hook技术? hook技术又被称为钩子技术。 在系统没有调用该函数之前,钩子程序就先捕获该消息,钩子函数先得到控制权,这时钩子函数既可以加工处理(改变)该函数的执行行为,还可以强制结束消息的传递。 简单来说,hook是一种截取信息、更改程序执行流向、添加新功能的技术。 通俗来说,就是一条高速公路,我们去追击一个罪犯(要截获的消息或事件),然后在他要经过的地方提前埋下埋伏,等到罪犯到来时,实...

weixin_43742894的博客 3321

UWB芯片DW3000之PDOA测向实现源码

本文详细介绍如何基于UWB芯片DW3000之PDOA测向的源码实现。

DT程序员的博客 2616

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

上一篇: NDIS HOOK 防火墙实现关键技术
下一篇: New Anti-Rootkit tools:NIAPAntiRootkitTools
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值