Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取

2023-11-06

目录(?)[+]

为什么要写这篇文章

1.      因为最近在学习《软件调试》这本书,看到书中的某个调试历程中讲了Windows的系统调用的实现机制,其中讲到了从Ring3跳转到Ring0之后直接进入了KiFastCallEntry这个函数。

2.      碰巧前天又在网上看到了一篇老文章介绍xxx安全卫士对Windows系统调用的Hook,主要就是Hook到这个函数

3.      刚刚做完毕业设计,对使用中断来实现系统调用的方式记忆犹新。

 

以上原因导致我最近眼前总是出现系统调用这个词,脑海中总是出现系统调用的实现方式,所以决定写篇文章清理一下思维。本文所有举例如无明确指明,均是在Windows XP SP3系统中获得。

 

本文的目的是探索一下Windows目前的系统调用的实现架构,介绍一种中规中矩的获取KiFastCallEntry函数地址的方法,但是在介绍之前还是要把该解释的解释清除。

 

Windows API和系统调用的关系

肯定会有人说Windows API就是系统调用系统调用就是Windwos API,是这样的么?负责任的说:不是这样的!

先从广义上来说,Windows API是对于整个Windows操作系统自身的程序代码之外的应用程序来说的,而系统调用Windows内核对于非内核程序代码之外的Windows系统程序代码来说的。也就是说系统调用要比Windows API低一个层次。一个Windows API是一个函数,这个函数可能会使用系统调用,请注意是可能,因为并不是所有的API都需要进入内核去完成这个API的功能。

 

Windows内核实现文件和应用层文件

在一个安装完成的Windows操作系统中可见并有效的内核实现文件是

C:\Windows\System32\ntoskrnl.exe

C:\Windows\System32\ntkrnlpa.exe

请注意有两个内核文件,其中第二个比第一个的名字少了os多了个pa,省去的os没有任何意义,但是多出来的pa所代表的意思是PAE(物理地址扩展),这是X86CPU的一个硬件特性,Windows启动之后根据当前系统设置是否开启了PAE特性会自动选择把其中一个作为内核加载到内存中。

为什么加了这么多限定词,因为ntoskrnl.exe这个文件名并不一定是这个文件的真实名称,可以从文件属性中看到

ntoskrnl.exe原始文件名为可能为ntoskrnl.exe或者ntkrnlmp.exe

ntkrnlpa.exe原始文件名为可能为ntkrnlpa.exe或者ntkrpamp.exe

可以发现其中的不同之处就是mpmp就是Multi-processor(多处理器,也可以理解为多核,因为IA-32架构对多核处理器的编程和多处理器的编程是相似的机制)。为什么会出现这中情况呢?因为这完全是由计算机硬件的不同配置导致的。当安装Windows操作系统的时候,Windows安装程序会自动检测机器的CPU特性,根据CPU的核心数来确定使用哪一套内核。如果是单核心就只复制ntkrnlpa.exentoskrnl.exe到系统目录下,如果是多核心就复制ntkrnlpamp.exentoskrnlmp.exe到系统目录下,所以如果你有一台单核心CPU的机器,有一天你换了双核的CPU却没有重新安装操作系统,那么你就不会在看到熟悉的Windows启动画面了。类似这两个文件的还有一个文件C:\Windows\System32\hal.dll,这是Windows的硬件抽象层程序文件,这个就不做具体介绍了。额外补充一个不同的硬件配置所需要的文件列表:

 

Standard PC

hal.dll 
ntkrnlpa.exe 
ntoskrnl.exe

Advanced Configuration and Power Interface (ACPI) PC

halacpi.dll---->hal.dll 
ntkrnlpa.exe 
ntoskrnl.exe

ACPI Uniprocessor PC

halaacpi.dll--->hal.dll 
ntkrnlpa.exe 
ntoskrnl.exe

MPS Uniprocessor PC

halapic.dll---->hal.dll 
ntkrnlpa.exe 
ntoskrnl.exe

ACPI Multiprocessor PC

halmacpi.dll--->hal.dll 
ntkrpamp.exe--->ntkrnlpa.exe 
ntkrnlmp.exe---->ntoskrnl.exe

Compag SystemPro Multiprocessor or 100% Compatible

halsp.dll---->hal.dll 
ntkrpamp.exe--->ntkrnlpa.exe 
ntkrnlmp.exe--->ntoskrnl.exe

MPS Multiprocessor PC

halmps.dll----->hal.dll 
ntkrpamp.exe----->ntkrnlpa.exe 
ntkrnlmp.exe--->ntoskrnl.exe

Silicon Graphics Visual Workstation

halsp.dll---->hal.dll 
ntkrpamp.exe----->ntkrnlpa.exe 
ntkrnlmp.exe---->ntoskrnl.exe

 

不论什么配置,一旦系统安装完成后,对我们来说可见的内核文件就只有两个ntoskrnl.exentkrnlpa.exe。这两个文件中的代码就是运行于RING0下的内核代码,他们里面所包含了真正的系统调用的代码。我们用Dependency Walker看一下:

(P1)

 

可以看到很多函数,他们之中有些是系统调用,会和RING3的程序代码有联系,有些仅仅是内核中的函数,只跟内核中其他的代码有联系。有一点需要说,在用Windbg调试内核的时候,无论系统使用的是哪个内核文件,Windbg都会把这个内核文件的符号(模块名)识别为nt。所以如果我们要查看内核中的NtOpenFile函数的反汇编,只需要输入一下命令

u nt!NtNtOpenFile

如下图:

(P2)

下面再说包含Windows API的文件,这个就非常多了,最基础的User32.dllNtdll.dllKernel.dll这三个文件包含了Windows系统相关的绝大多数API,当然还有其他函数簇比如包含socket函数簇的ws2_32.dll等等,这些dll中都导出了大量的API函数以及结构。这些函数都是运行在RING3层的代码,有些会跟内核层中的代码发生联系,有写也不会,就是上面提到的Windows API不一定会使用系统调用。比如我们举个简单的例子,拿CharNextA这个Windows API来说,这个API是在User32.dll中实现的。我们可以反汇编一下看看这个API的具体实现。

(P3)

可以看到这个函数在ret之前只有一个跳转je并且目标代码仍然在本函数内,而且没有任何中断或者快速系统调用,所以这个函数并没有离开RING3层,也就是说当你编写一个程序调用了这个API之后,这个API并没有把你的程序流程带入RING0的内核层代码。

 

Windows API使用系统调用的方法

通过中断实现系统调用

Windows API如果设涉及到系统调用就要由RING3进入RING0,这就牵扯到了X86保护模式下有特权级变化的控制转移。在早期的CPU(Pentium II之前),没有快速系统调用这个机制,所以能用来进行特权级变化的控制转移的机制只有通过中断实现,保护模式下的中断的实现方式是通过IDT表来实现,IDT表中存放的是一种特殊的X86段描述符——门描述符,门描述符的格式如下

(P4)

可以看到其中有一个Selector字段和一个Offset字段,并且是不连续的,这里只介绍这两个字段的含义,其他字段的含义这里不再赘述,有兴趣的话可以自己去看下保护模式相关资料。说到底这个门描述符的作用就是描述一个程序段,对我们来说重要的就是SelectorOffset字段了,因为Selector可以帮我们找到它所描述的程序的【段】,Offset就是程序在【段】内的【偏移】,有了【段】和【偏移】就可以确定程序的线性地址。那么我们来试着找一找Windows通过中断来实现系统调用时候的流程!不会用Windbg的程序员不是好的狙击手。

首先用Windbg打开一个Calc.exe或者其他的普通应用程序,然后键入命令:

u ntdll!KiIntSystemCall

(P5)

如果有疑问为什么直接来到这个函数,现在先不忙解释,后面再说。可以看到这个函数中

int 2Eh

这一句汇编代码,我们知道了系统调用了2E号中断,从而进入了系统内核,知道了中断号下面我们要做的就是找到这个中断的服务程序,也就是RING3进入到RING0之后的第一条指令在哪里。下面就进入内核调试模式。通过

!pcr

查找IDT的线性地址

(P6)

找到了IDT的线性地址:0x8003f400,前面说过IDT中存放的是门描述符,每一个门描述符占用8个字节,所以我们要找的第2e个门描述符的地址应该为0x8003f400+2e*8,然后我们通过如下命令:

dq /c 1 8003f400+2e*8

查看内存内容:

(P7)

看到第一行的八个字节就是我们要找的2e号中断所对应的门描述符。根据门描述符的格式计算,得到这个门描述符中包含的

Offset【偏移】 = 0x8053e4a1

Selector = 0x0008

【偏移】已经找到了,下面就剩【段】了,【段】可以通过Selector【选择子】找到,这里需要说下【选择子】,选择子占用2个字节,格式如下

(P8)

选择子是真正可以存放在保护模式下的段寄存器中的结构,既然它被放在段寄存器中,那么通过它必然能够找到段的信息,保护模式下的段是通过段描述符来描述的,描述符的具体分类有三种:存储段描述符,系统段描述符,门描述符,这里只介绍存储段描述符,其他的请自行查阅保护模式相关资料。存储段描述符格式如下:

(P9)

可以看到存储段描述里包含了基址,界限和属性。对我们来说只要找到基址就行了。存储段描述符是保存在GDT中的,而选择子则包含了【描述符索引】即这个选择子所指向的描述符在GDT中的索引号,比如我们刚才计算得到的选择子Selector = 0x0008,其中索引号为1,就是说我们要找的段的段描述符在GDT中的第1项。由此可知,我们要找到【段】还需要找到段描述符,这个算法跟从IDT中找门描述符是一样的,先找到GDT的地址,从刚才的!pcr命令执行结果看到GDT = 0x8003f000,一个描述符占用8个字节,我们要找第一个描述符,计算得到描述符的地址为:0x8003f000+8*1,执行命令

dq /c 1 8003f000+1*8

得到结果:

(P10)

根据上述存储段描述符的格式计算得到该段的基地址为0x000000所以费劲千辛万苦找到了【段】=0x00000,现在【段】和【偏移】都找到了,那么我们要找的一个线性地址就找到了:

【段】:【偏移】 = 0x8053e4a1

反汇编看看这个地址的代码!

u 8053e4a1

得到结果:

(P11)

是这个函数nt!KiSystemService。为了验证我们没有计算错误,可以用Windbg直接显示2E号中断所对应的中断服务程序,执行命令:

!idt 2e

(P12)

可以看到通过脑力算出的结果与Windbg dump出来的结果是一样的,证明了我们的算法是没有问题的。

这样我们先总结一下使用中断实现系统调用时候RING3RING3的函数接续:

NtDll!KiIntSystemCall > Nt!KiSystemService

使用快速系统调用机制

Pentium II系列开始的CPU引入了快速系统调用这一特性,增加了两条指令SYSENTERSYSEXIT(AMD CPU中的指令为SYSCALLSYSRET)。这一机制的实现就是专门用于解决操作系统的系统调用的性能问题的,这种机制实现的控制转移比中断系统要快很多,因为转移的目标地址是存放在MSR寄存器内,而中断实现的系统调用目标地址存放在内存中的IDT中,所以能提高执行速度。

下面看一下在应用层是在哪里调用了这条指令的:

(P13)

可以看到在ntdll!KiFastSystemCall中有这条指令。

SYSENTER指令的工作机制是在调用SYSENTER指令前,软件必须通过下面的MSR寄存器,指定0层的代码段和代码指针,0层的堆栈段和堆栈指针:

1. IA32_SYSENTER_CS:一个32位值。低16位是0层的代码段的选择子。该值同时用来计算0层的堆栈的选择子。

2. IA32_SYSENTER_EIP:包含一个32位的0层的代码指针,指向第一条指令。

3. IA32_SYSENTER_ESP:包含一个32位的0层的堆栈指针。

MSR寄存器可以通过指令RDMSR/WRMSR来进行读写。寄存器地址如下表。这些地址值在以后的intel 64IA32处理器中是固定不变的。

MSR

地址

IA32_SYSENTER_CS

174H

IA32_SYSENTER_ESP

175H

IA32_SYSENTER_EIP

176H

当执行SYSENTER,处理器会做下面的动作:

1.IA32_SYSENTER_CS从取出段选择子加载到CS中。

2.IA32_SYSENTER_EIP取出指令指针放到EIP

3.IA32_SYSENTER_CS的值加上8,将其结果加载到SS中。

4.IA32_SYSENTER_ESP取出堆栈指针放到ESP寄存器中

5.切换到0层。

6.EFLAGSVM标志已被置,则清除VM标志。

7.开始执行选择的系统过程。

 

     又看到了【选择子】,了解了执行流程,下面还可以手工一步步计算出SYSENTER指令行执行CPU取出的第一条内核指令到底在哪里。有了上面的计算过程,这次计算就不需要写的很详细了,目标还是要找到【段】和【偏移】,很明显【偏移】放在MSR176号地址中,Windbg用如下指令读取MSR

      rdmsr 176

(P14)

【偏移】 = 0x8053e60

下面找【段】,依然是通过选择子来计算,选择子在MSR174号地址中存放

     rdmsr 174

(P15)

【选择子】 = 0x0008,跟之前的选择子一样,这里就不用再去计算了,从刚才的结果中知道这个选择子指向的描述符所描述的内存基址是线性地址0x0000

所以我们要找的目标线性地址为【段】:【偏移】 = 0x8053e60

下面反汇编一下这个地址:

(P16)

看到是函数Nt!KiFastCallEntry

总结一下使用快速系统调用机制的时候RING3RING3的函数接续:

NtDll!KiFastSystemCall > Nt!KiFastCallEntry

完整的Windows API使用系统调用的过程

XP系统之前,Windows只实现了一种系统调用的方式,那就是通过INT 2E号中断来实现的,所以从RING3RING0之后的第一个函数一定是nt!KiSystemService,这个函数就是核心的系统调用分派函数,但是XP开始,Windows系统开始使用快速系统调用这一机制了,但是并没有失去对中断方式的支持,所以XP之后的系统都是两种实现方式共存的。具体做法我们可以用Windbg来继续探索,下面的工作就要在RING3来做了,因为我们要分析一个完整的Windows API使用系统调用的过程。在这之前需要先说一下有关Nt*Zw*函数的问题。在应用层的Ntdll.dll中有大量的Nt开头的函数和Zw开头的函数,并且都是配对出现,他们所指向的地址都是相同的,所以他们的实现是完全相同的,只不过是别名问题。我们可以用Depdency Walker查看他们的入口地址发现都是相同的,也可以用Windbg反汇编看,关于这一点没什么好说的了,网上很多资料都有说。那我们就可以随便选择一个Nt开头的函数来进行分析,或者Zw开头的都是一样的。内核中也存在这样的函数,但是Nt开头的函数是真正的函数实现,Zw开头的函数是通过nt!KiSystemService函数最终调用的Nt开头的函数。我们选择NtOpenFile函数,需要说明的是这个函数是未导出的,我们在编程的时候使用的是kernel32.dll中导出的OpenFile或者OpenFile,最终是要进入NtOpenFile,从KERNEL32.dllNtdll.dll的过程省略。先反汇编NtOpenFile看看:

(P17)

看到在NtOpenFile函数中红色标注的代码,把一个内存中的一个dwrod取到了edx中,这个内存的符号为SharedUserData!SystemCallStub,然后跳转到edx中的值,所以edx中应该是一个函数的地址,我们看一下这个地址是什么

(P18)

看到这个地址中存放的地址是0x7c92e510,反汇编这个地址

(P19)

看到SharedUserData!SystemCallStub保存的是快速系统调用的入口函数的地址,其中通过sysenter进入内核,进入内核之后的过程上面已经介绍过了。

现在就可以总结一下一个Windows API如果使用了系统调用之后的流程了:

无论在何处直接调用了RING3API并且需要使用系统调用,最终都会通过Ntdll.dll这个函数来进入内核,例如一个函数OpenXXX,无论其在哪个DLL实现,最终都要进入Ntdll.dll这个函数中的NtOpenXXX,在该函数中的内容就是读取一个用户共享数据区中的一个变量SytemCallStub,这个变量的值就是包含实现特权级变化的控制转移代码的函数入口,其实就是ntdll!KiFastSystemCall的地址,在这个函数中使用了SYSENTER指令,可以直接进入内核的nt!KiFastCallEntry,这个函数会调用nt!KiSystemService这个函数,这个函数的任务是查找SSDT中对应系统调用号的系统调用的实现地址nt!NtOpenXXX

 

本来我是想做一个推测:在XP系统中通过中断方式实现系统调用的代码仍然存在,那么我们能不能根据需要选择我们希望使用的系统调用的实现方式呢?产生这个想法的原因是Windows并没有直接把实现特权级变化的控制转移代码的函数入口硬编码到每一个API中,而是使用了一个变量—SharedUserData!SytemCallStub中,既然这样实现肯定是为了可以方便切换这个函数的地址,在现在的XP以及更新的操作系统中,这个变量中存放的是ntdll!KiFastSystemCall,就是通过快速系统调用的方式来实现系统调用,那么如果我们修改这个变量的值,使其等于ntdll!KiIntSystemCall的话,是不是就可以改变整个系统的系统调用方式为中断方式呢?关于这个猜想还我还没有做下验证,打算过几天再验证。

 

nt!KiFastCallEntry函数地址的获取

下面说一下nt!KiFastCallEntry这个函数,无论通过何种系统调用的实现方式,都会调用这个函数来进行系统调用,所以这个函数也就成了一是十分重要的领地,就相当于兵家必争之地,无论是安全软件还是恶意软件。但是这个这个函数地址的获取还是有一点技巧的。

在这里先说一下XXX安全卫士的获取nt!KiFastCallEntry这个函数地址的方式,因为网上有人分析过它的实现方式,并且被大量转载,所以这里只是简单的提一下。我们已知的信息是,Windows的凡是涉及系统调用的API在内核中的调用顺序是:

快速系统调用:nt!KiFastCallEntry->Nt*

中断方式系统调用:nt!KiSystemService-> nt!KiFastCallEntry->Nt*

所以为了过滤系统调用,只要Hooknt!KiFastCallEntry这个函数就一定能拦截所有的系统调用。XXX安全卫士的做法是先Hook住了一个nt!NtSetEvent函数,当进入这个函数的时候利用栈回溯,找到当前函数的返回地址,这个地址一定是在上层函数内的,得到这个地址就以后,就可以根据特征码搜索需要Inline Hook的目标地址了。借助nt!ZwCreateFile函数来动态跟踪分析,如下图:

(P20)

很多人说这种方法巧妙,通过栈回溯找到目标函数地址域内的一地址,然后特征码匹配,为何不直接找到函数入口然后直接特征码匹配呢?栈回溯的方法固然看起来很巧妙,可是如果内核中对nt!KiFastCallEntry函数启用了FPO(帧指针优化),那这种方法就完全被挫败了,所以这种方法并不能称为完美。

 

网上也有很多其他方法来获取nt!KiFastCallEntry函数入口地址,有暴力搜索的,也有通过MSR寄存器的。通过MSR寄存器读取的确是一种中规中矩的方法,但是看过不少代码,都是建立在一个假设上:nt!KiFastCallEntry的段基址一定是线性地址0x00开始。这些代码都直接忽略了对MSR 174号地址内的段选择子的处理,完整的做法应该利用本文中之前的方法计算段和偏移求得nt!KiFastCallEntry的入口地址,由于汇编语言处理这些计算相对方便,所以本人用汇编实现了一个得到nt!KiFastCallEntry函数地址的函数。代码如下:

 

[html]  view plain copy
  1. #define IA32_SYSENTER_CS 174H  
  2. #define IA32_SYSENTER_ESP 175H  
  3. #define IA32_SYSENTER_EIP 176H  
  4.   
  5. ULONG GetAddressOfKiFastCallEntry()  
  6. {  
  7.     ULONG dwAddress = 0;  
  8.     __asm  
  9.     {  
  10.         jmp func_main  
  11. vgdtr:  
  12.         _emit 0x00  
  13.         _emit 0x00  
  14.         _emit 0x00  
  15.         _emit 0x00  
  16.         _emit 0x00  
  17.         _emit 0x00  
  18.         _emit 0x00  
  19.         _emit 0x00  
  20.   
  21. func_main:  
  22.         push eax  
  23.         push ebx  
  24.         push ecx  
  25.         push edx  
  26.         mov ecx, 0x174  
  27.         rdmsr  
  28.         mov ebx, eax        //Selector offset  
  29.           
  30.         sgdt vgdtr  
  31.         mov edx, vgdtr  
  32.         add edx, 0x02  
  33.         mov eax, [edx]      //GDT base  
  34.         add ebx, eax        //Selector base  
  35.   
  36.         mov edx, ebx  
  37.         add edx, 0x07  
  38.         mov eax, [edx]  
  39.         shl eax, 24;  
  40.         mov edx, ebx  
  41.         add edx, 0x02  
  42.         mov ecx, [edx]  
  43.         and ecx, 0x00FFFFFF  
  44.         add eax, ecx        //Address CodeSegment  
  45.         mov ebx, eax  
  46.   
  47.         mov ecx, 0x176  
  48.         rdmsr  
  49.         add eax, ebx  
  50.   
  51.         mov dwAddress, eax  
  52.   
  53.         pop edx  
  54.         pop ecx  
  55.         pop ebx  
  56.         pop eax  
  57.     }  
  58.   
  59.     return dwAddress;  
  60. }   

 

测试用驱动代码及结果如下图:

(P21)

(P22)

这个结果和我们用Windbg查看得到的是一样的。

 

这篇文章写的有点长,而且知识有点砸碎希望各位看过之后能理解。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取 的相关文章

  • ARM 64 协程切换上下文的汇编代码解读

    ARM 64协程切换上下文的汇编代码解读 贺志国 2023 8 11 在ARM 64位架构中 有一组通用寄存器 General Purpose Registers 一组浮点寄存器 Floating point Registers 和一组特殊
  • 王爽汇编语言课程设计1

    一 实验要求 在屏幕输出实验七中的数据 二 设计思路 1 将实验七的程序编写成一个子过程finishing 在主程序中调用 可以获得实验七种指定格式的table段数据 设置es bx指向table段中第一行 2 创建一个数据缓存区buffe
  • win32汇编基础概念

    一 关于寄存器 寄存器有EAX EBX ECX EDX EDI ESI ESP EBP等 似乎IP也是寄存器 但只有在CALL RET在中会默认使用它 其它情况很少使用到 暂时可以不用理会 EAX是WIN32 API 默认的返回值存放处 E
  • CSAPP-BinaryBomb实验

    目录 一 实验目的与要求 二 实验原理与内容 三 实验过程与结果 1 程序编码 汇编 2 拆解过程 Phase 1 Phase 2 Phase 3 Phase 4 Phase 5 Phase 6 Secret phase 一 实验目的与要求
  • 汇编中16进制装换成为其他进制(2,8,10)

    16进制装换成为其他进制关键在于得到键盘输入 并将它保存在BINARY的这个变量里面 宏定义直接调用 例子中有 DISP etc 子程序的话要注意对主程序的信息的保护和恢复 我在这里使用的是在子程序里面去保护主程序的方式 你也可以在主程序调
  • linux汇编编译器:GAS和NASM的比较

    GAS即GNU AS汇编编译器 其属于AT T风格 我们常用的GNU的产品还有GCC G NASM是Linux平台下常用的汇编编译器 是intel风格的汇编编译器 MASM是Windows平台下的汇编编译器 也使用Intel风格 我们学80
  • 函数的引用返回

    引用是给变量取一个别名 所以引用传递会直接进行变量本身的传递 它的最大好处是可以把别处对变量的改变保留下来 第二好处是它提高了性能 如果函数的返回值是一个引用 那么 如上文所说 它会节约一组构造 赋值和析构过程 但是 函数返回引用往往会带来
  • 链接、装载与库——编译与链接

    从第二章开始不再按照目录的顺序总结 而是将大块知识点总结在一起 第二章 编译和链接 集成开发环境 IDE 一般都将编译和链接的过程一步完成 此过程成为构建 Bulid 但其掩盖了系统软件运行机制 gcc hello c a out 一个可执
  • IDA使用之旅(一)用IDA查看最简单的sys文件

    转载请标明是引用于 http blog csdn net chenyujing1234 欢迎大家拍砖 本系列内容是我根据 知其所以然论坛 博主录制的学习视频 做的笔记 使用的IDA软件版本 IDA pro 5 5 参考下载地址 http w
  • x86-64 汇编基础 ---- 记读 《CS: APP》

    x86 64 汇编基础 记读 CS APP 通常情况下 使用现代的优化编译器产生的代码至少与一个熟练的汇编语言程序员手工编写的代码一样有效 1 看懂汇编码 1 汇编码的格式 ATT格式 这是GCC OBJDUMP和其它一些工具的常用格式 由
  • 汇编——寄存器的分类和功能

    在汇编中 个人感觉最重要的部分其实就是寄存器了 这次我们了解一下寄存器的分类和功能 先说一下寄存器是什么吧 其实就是一部分的空间 我们可以使用这些空间来存储内容 寄存器的空间都是16位的 80x86中 后来有增长 也就是1个字的空间 堆栈则
  • libtool的作用及应用

    gcc library makefile archive command object 注意 本文为转载 原文也是转载 但是为了尊重他人得劳动成果 我将将转载网址贴出来 libtool常见于autoconf automake 单独用的例子很
  • 汇编语言+IDA安装问题解决汇总

    利用汇编语言计算机和人类链接更为便捷如下图所示 寄存器 简单讲就是CPU可以存储数据的器件 一个CPU可以有多个寄存器 AX BX是两个不同的寄存器 16位处理器有14个寄存器 AX BX CX DX SI DI SP BP IP CS S
  • 汇编宏伪指令介绍

    1 汇编宏伪指令介绍 macro macname macargs endm 1 macro 和 endm 表示宏定义的开始和结束 2 macro 后面接着宏定义的名字 然后是参数 参数后面的宏定义的实现 3 在宏定义中使用参数 需要添加前缀
  • 8259初始化命令字(ICW1-ICW4)

    8259A的中断操作功能很强 包括中断的请求 屏蔽 排队 结束 级联以及提供中断类型号和查询等操作 并且其操作的方式又有不同 它既能实现向量中断 又能进行中断查询 它可以用于16位机 也可用于8位机 因此 使用起来感到复杂且不好掌握 为此
  • asm: 实现打印“Hello, world!“

    使用汇编打印 Hello world 实现打印 Hello world 的汇编代码 代码详细剖析 实现打印 Hello world 的汇编代码 我们来直接贴代码 section text global start start mov edx
  • 常见汇编指令整理

    本文会整理在逆向中常见的指令汇总 目录 汇编符号 汇编指令的组成 mov movzx lea xchg 加法指令 减法指令 带进位加法 带进位减法 自增自减 乘法运算 除法运算 and or xor not shl shr 逻辑指令 字符串
  • C语言深入学习--checklist4:宏、枚举、switch

    宏 1 宏的本质是什么 函数 语句 类型定义 或者其它 预编译器的文本替换 1 你知道语言设计者为什么设计宏吗 这些原因目前是否成立 在 C程序中 可以用宏代码提高执行效率 宏代码本身不是函数 但使用起来象函数 预处理器用复制宏代码的方式代
  • DOSBOX 快捷键及 MS-DOS 命令

    1 全屏 退出全屏 alt enter 2 释放鼠标 ctrl F10 3 exit 退出DOSBOX 4 dir 显示目录内容 可选参数 w 只显示文件名 P 显示部分内容 exe 筛选出可执行文件 5 cd 进入目录 cd 退回上一级目
  • 【go语言】AST抽象语法树详解&实践之扫描代码生成错误码文档

    背景 为了能识别出代码中抛出错误码的地址和具体的错误码值 再根据错误码文件获取到错误码的具体值和注释 方便后续的排错 这里使用AST进行语法分析获取到代码中的目标对象 一 编译过程 在开始解析代码之前先补充了解一下编译过程 编译过程是将高级

随机推荐

  • CobalStrike的部署(附带资源)

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 CobalStrike是什么 二 CobalStrike的部署 总结 前言 作为刚入门网安的小白 挺久之前 就曾听说过CobalStrike这样的一个Re
  • 10LinuxC线程学习之pthread_detach函数,错误返回值分析及其案例

    1 pthread detach函数 int pthread detach pthread t thread 功能 1 实现线程分离 不再受主线程管理 由系统接任 线程结束后 其退出状态不由其他线程获取 而直接自己自动释放 网络 多线程服务
  • TypeScript 封装 Axios

    TypeScript 封装 Axios TypeScript 封装 Axios 为什么需要封装 axios 因为直接在项目中使用 axios axios 的 api 将会嵌入代码的各个地方 耦合程度太高 如果后期更换 Ajax 请求库 将会
  • QT学习笔记02信号与槽简介

    标准信号和槽 信号槽是 Qt 框架引以为豪的机制之一 所谓信号槽 实际就是观察者模式 当某个事件发生之后 比如 按钮检测到自己被点击了一下 它就会发出一个信号 signal 这种发出是没有目的的 类似广播 如果有对象对这个信号感兴趣 它就会
  • OpenTelemetry 项目解读

    点击一键订阅 云荐大咖 专栏 获取官方推荐精品内容 学技术不迷路 随着分布式应用越来越普遍 分布式应用需要依赖强大的可观测性设施来提供监控保障 强大的可观测性设施需要依赖高质量的遥测数据 虽然已经有许多开源或者商业供应商提供了遥测数据监测采
  • 华为eNSP实验-防火墙模拟配置(采用ping命令逐步分析)

    ensp防火墙模拟配置 采用ping命令逐步分析 1 各设备的IP地址配置 按如图所示配置好各个设备对应的IP地址 注意点 1 图中cloud2云处需要关联电脑上对应的虚拟网卡 2 实验中我使用的是华为USG6000V防火墙 需要下载软件包
  • 用批处理写修改注册表的命令

    一般书写格式 reg add 注册表路径 v 值名 t 要修改的数值类型 d 想要输入的数据 f 这个选项可根据情况自行添加 意为不用提示就强行改写现有注册表项 如果在批处理中不想显示出命令执行过程可以再reg前面加入 后面加上 gt nu
  • 使用python安装nginx

    肯定有小伙伴疑问哈 安装nginx仅仅需要几条命令如果只是单单安装简单使用os system os Popen几乎就足以完成 那么为什么要写这么多呢 笔者在写这段代码的时候一个是想让代码更加美观 显得比较专业 另一方面无论安装什么 配置什么
  • 前端 js实现模糊搜索

    前端 js实现模糊搜索 template
  • 全世界最好的编辑器VIM之Windows配置(gvim)

    全世界最好的编辑器VIM之Windows配置 gvim vundle插件管理 NERDTree插件 ctrlp插件 vim nerdtree tabs插件等 vim本来就是很强大 很方便的编辑器 再加上这些杀手级的插件 那就真的无敌了 官方
  • Caused by:org.springframework.beans.factory.NoSuchBeanDefinitionException:No qualifying bean of type

    今天使用Junit单元测试写了个测试spring的AnnotationConfigApplicationContext 的测试方法 代码如下 public class TestApplicationContext Test 较为经典的容器
  • 大数据学习-4.Hadoop运行环境搭建(二)

    文章目录 一 下载JDK和Hadoop安装包 二 安装JDK 三 安装Hadoop 1 单机模式搭建 2 分布式模式搭建 一 下载JDK和Hadoop安装包 下载地址 阿里云 提取码 q6y6 二 安装JDK 测试主机是否有java环境 如
  • 电磁场与电磁波第二章 电磁场的基本规律

    文章目录 第二章 电磁场的基本规律 电荷守恒定律 1 电荷与电荷密度 2 电流与电流密度 3 电荷守恒定律 电流连续性方程 真空中静电场的基本规律 1 库仑定律 电场强度 1 电场强度 2 几种典型电荷分布的电场强度 2 静电场的散度与旋度
  • 博弈论中存在的先动优势和后动优势

    博弈论中存在的先动优势和后动优势 完全信息动态博弈 Stackel berg寡头竞争模型属于先动优势 轮流出价的讨价还价模型 当均衡结果与T无关的时候且 1 贴现因子 2 1 双方无限的耐心 时 存在后动优势 因为他将拒绝任何自己不能得到全
  • idea中java源码英文注释的翻译

    效果展示 操作步骤两步 安装translation插件 设置翻译引擎 安装translation插件 选择该插件 安装好后重启idea即可使用 设置翻译引擎 这里用有道翻译演示 注册好后在业务里面创建翻译接口 创建好后把id和密钥复制填上去
  • 入门深度学习——基于全连接神经网络的手写数字识别案例(python代码实现)

    入门深度学习 基于全连接神经网络的手写数字识别案例 python代码实现 一 网络构建 1 1 问题导入 如图所示 数字五的图片作为输入 layer01层为输入层 layer02层为隐藏层 找出每列最大值对应索引为输出层 根据下图给出的网络
  • java手工注入bean,Spring注入Bean的一些方式总结

    通过注解注入Bean 背景 我们谈到Spring的时候一定会提到IOC容器 DI依赖注入 Spring通过将一个个类标注为Bean的方法注入到IOC容器中 达到了控制反转的效果 那么我们刚开始接触Bean的时候 一定是使用xml文件 一个一
  • 常见数据库安装

    简介 本文记录了常用数据库 MySQL PostgreSQL MSSQL Oracle Redis MongoDB在Windows 及Linux Ubuntu 下 MSSQL Oracle除外 的安装 macOS可参考前两者 解决了Orac
  • win10家庭版找不到组策略gpedit.msc的解决方法

    废话不多说 直接上方法 注意的事项我会再后面讲到 1 打开记事本 在记事本中保存如下批处理内容 echo off pushd dp0 dir b systemroot Windows servicing Packages Microsoft
  • Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取

    Windows系统调用架构分析 也谈KiFastCallEntry函数地址的获取 windows api 汇编 hook 存储 system 目录 为什么要写这篇文章 1 因为最近在学习 软件调试 这本书 看到书中的某个调试历程中讲了Win