解决error A2108: use of register assumed to ERROR
作者:admin 日期:2009-12-04
hook api 反OD调试的一种思路
作者:admin 日期:2009-12-02
用OD脱壳的基本方法
作者:admin 日期:2009-12-01
引导程序的编写
作者:admin 日期:2009-11-24
对于一个操作系统来说,如果没有一个引导程序是无法工作的。但是,引导程序却往往不被认为是操作系统的一部分。这也是为什么我们在安装多个操作系统的时候可以使用linux来引导windows,也可以使用windows的引导程序引导linux。但是,这里的引导是有附加条件的。那就是你必须做一些改动。不过,这个不是我们要讨论的。
那么,什么是引导程序呢?引导程序到底做了那些工作?他有起到了什么作用?有一个比喻是很贴切的。那就是我们可以把引导程序想像成药引子,如果说操作系统被看成是一副中药的话。
那么引导程序做了那些工作呢?不同的引导程序实现的具体功能是不一样的。比如GRUB和NTLD的功能就千差万别。不过有一句话道出了其中的共性,那就是“一个好的引导程序相当于一个小的操作系统”。
GRUB就是一个好的引导程序,他有shell,可以访问多种文件系统(包括ext2、FAT12/16/32、iso等等)。他甚至还包含了简单的内存管理。
不过无论他多么强大,他也只是一个引导程序。我们现在就来看一下如何写我们自己的引导程序。
那么,什么是引导程序呢?引导程序到底做了那些工作?他有起到了什么作用?有一个比喻是很贴切的。那就是我们可以把引导程序想像成药引子,如果说操作系统被看成是一副中药的话。
那么引导程序做了那些工作呢?不同的引导程序实现的具体功能是不一样的。比如GRUB和NTLD的功能就千差万别。不过有一句话道出了其中的共性,那就是“一个好的引导程序相当于一个小的操作系统”。
GRUB就是一个好的引导程序,他有shell,可以访问多种文件系统(包括ext2、FAT12/16/32、iso等等)。他甚至还包含了简单的内存管理。
不过无论他多么强大,他也只是一个引导程序。我们现在就来看一下如何写我们自己的引导程序。
new和malloc的区别(转)
作者:admin 日期:2009-11-22
对待64位windows
作者:admin 日期:2009-11-22
还记得640K内存就足够的好日子吗?那记得是什么时候,它显得捉襟见肘了吗?这是一个日新月异的时代,我们发明了各种方法,以在有限的寻址空间内,映射更多的内存:首先,是“扩充内存”(EMM),起初它只是一张硬件“卡”,以64K或128K HASH(0x80b9d4)为界,切换64K的HASH(0x80b9d4)页到DOS寻址空间内;然后,我们又看到了“扩展内存”(XMS),它使保护模式映射到更多的64K区域成为了可能。而所有这些,都只是给了程序一个权宜之计,我们真正需要的是一个更大的寻址空间,这时,32位寻址就成了大众欢迎的、暂时的“止痛片”。
如果640K对任何人都足够,那么2GB(Windows实际上可寻址到4GB)对大多数应用程序来说都绰绰有余,但是,仍有一些程序要求越来越大的寻址空间,这样,人们又发明了寻址窗口扩展(Address Windowing Extension AWE)和实体地址延伸(Physical Address Extension PAE)等等映射技术。今天,64位处理器和两个新版本的64位Windows来到了我们身边,与16位到32位的变化不同的是,大多数今天我们使用的程序,都没有突破2GB的寻址空间,那么新处理器有什么用呢?我们何必在意它呢。
诚然,在可预见的未来,我们将继续编写32位程序,但不管怎么说,在这两年里,64位CPU进入桌面电脑已成了不争的事实。AMD Athlon64和Opteron处理器随处可见,而主板生产商也推出了相应的主板,价格上与同级别32位主板相近;Intel,一开始掉在了安腾处理器(Itanium)的钱眼里,为了赶上老对手,匆匆于2004年底发布了“32位扩展架构”的至强(Xeon)处理器,技术名称为IA32E或EM64T。由于Intel的安腾处理器缺乏向后兼容,现有的二进制代码运行效率不高,一如当年Win16到Win32的转变,导致OS/2的陨落和Windows在桌面的崛起一样,AMD此时看到了也抓住了这个机会。虽然Intel的处理器可高效运行本地(native)64位代码,但从经验来说,32位程序在AMD64和EM64T架构上效率都不是很高,而Microsoft微软,由于吸取了操作系统源代码兼容性的教训,所以它从现今的Win32源代码从发,构建一个64位版本的系统应该不是件难事。
如果640K对任何人都足够,那么2GB(Windows实际上可寻址到4GB)对大多数应用程序来说都绰绰有余,但是,仍有一些程序要求越来越大的寻址空间,这样,人们又发明了寻址窗口扩展(Address Windowing Extension AWE)和实体地址延伸(Physical Address Extension PAE)等等映射技术。今天,64位处理器和两个新版本的64位Windows来到了我们身边,与16位到32位的变化不同的是,大多数今天我们使用的程序,都没有突破2GB的寻址空间,那么新处理器有什么用呢?我们何必在意它呢。
诚然,在可预见的未来,我们将继续编写32位程序,但不管怎么说,在这两年里,64位CPU进入桌面电脑已成了不争的事实。AMD Athlon64和Opteron处理器随处可见,而主板生产商也推出了相应的主板,价格上与同级别32位主板相近;Intel,一开始掉在了安腾处理器(Itanium)的钱眼里,为了赶上老对手,匆匆于2004年底发布了“32位扩展架构”的至强(Xeon)处理器,技术名称为IA32E或EM64T。由于Intel的安腾处理器缺乏向后兼容,现有的二进制代码运行效率不高,一如当年Win16到Win32的转变,导致OS/2的陨落和Windows在桌面的崛起一样,AMD此时看到了也抓住了这个机会。虽然Intel的处理器可高效运行本地(native)64位代码,但从经验来说,32位程序在AMD64和EM64T架构上效率都不是很高,而Microsoft微软,由于吸取了操作系统源代码兼容性的教训,所以它从现今的Win32源代码从发,构建一个64位版本的系统应该不是件难事。
PEB结构----枚举用户模块列表(图)
作者:admin 日期:2009-11-22
本文在主主要以上述两篇文章为基础,对PEB的结构进行了详细的分析,重点是在揭示PEB结构中的list—entry的应用,并且以C语言Code进行实证。
本文主要分为四个部分,第一部分说明PEB地址如何获得;第二部分说明PEB的框架结构;第三部对PEB中的List-Entry结构进行了详细剖析,第四部分给出了枚举用户模块列表的代码。
--------------------------------------------------------------------------------------------------------------
本文主要分为四个部分,第一部分说明PEB地址如何获得;第二部分说明PEB的框架结构;第三部对PEB中的List-Entry结构进行了详细剖析,第四部分给出了枚举用户模块列表的代码。
--------------------------------------------------------------------------------------------------------------
为PE文件添加节(汇编代码)
作者:admin 日期:2009-11-22
WINDBG使用教程
作者:admin 日期:2009-11-20
小览call stack(调用栈)
作者:admin 日期:2009-11-20
进程防调试的处理办法
作者:admin 日期:2009-11-20
在Ring3上实现文件碎甲(文件解锁)
作者:admin 日期:2009-11-16
作者:cbns888
一.概述:
如果一个病毒文件被植入正在运行的进程中,我们想要清除它时系统总会提供无法删除;有时编辑文件的进程被意外中止而文件句柄没有正确释放,导致此文件无法进行改写操作。现在我们会使用Unlocker之类的小工具去解锁,但在编写程序的可能会需要把这些功能包含在自己的代码中,本文就是自己写代码实现”如何关闭已经被加载的DLL或是正在使用的文件”功能,使用文章中的方法能很方便的完成文件解锁功能。
按最初的想法准备在ring0中完成这些功能,但在查找资料的过程中发现既然我们能在ring3中做,为什么不让这些方法更通用一些呢。其实功能实现并不难,主要是前期从哪里入手比较麻烦。
我们知道无论是动态库或是文件在加载到进程中时,总会有一个指向它的指针,如果让进程释放这段指针,那么这些文件就不会被系统锁定。下面将是我们的需要实现文件解锁功能而分解出的步骤
一.概述:
如果一个病毒文件被植入正在运行的进程中,我们想要清除它时系统总会提供无法删除;有时编辑文件的进程被意外中止而文件句柄没有正确释放,导致此文件无法进行改写操作。现在我们会使用Unlocker之类的小工具去解锁,但在编写程序的可能会需要把这些功能包含在自己的代码中,本文就是自己写代码实现”如何关闭已经被加载的DLL或是正在使用的文件”功能,使用文章中的方法能很方便的完成文件解锁功能。
按最初的想法准备在ring0中完成这些功能,但在查找资料的过程中发现既然我们能在ring3中做,为什么不让这些方法更通用一些呢。其实功能实现并不难,主要是前期从哪里入手比较麻烦。
我们知道无论是动态库或是文件在加载到进程中时,总会有一个指向它的指针,如果让进程释放这段指针,那么这些文件就不会被系统锁定。下面将是我们的需要实现文件解锁功能而分解出的步骤
机器狗穿透还原的磁盘级文件读写完整驱动代码
作者:admin 日期:2009-11-09
虚拟内存与物理地址扩展(PAE)
作者:admin 日期:2009-10-25
Windows的虚拟内存并非简单的指位于我们硬盘上的那个pagefile.sys文件,或者是在内存装不下的时候用于应急的“模拟内存”。事实上Windows的每一个进程都会同时用到物理内存和虚拟内存。
[img]http://img.zdnet.com.cn/1/765/liGS541OHroM.jpg[/img]
在Windows系统中,任何一个进程都会被赋予其自己的虚拟地址空间(虚拟内存),该虚拟地址空间可以覆盖了一个相当大的范围。对于一个32位进程,其可以拥有的地址空间为2^32=4GB,这使得一个指针可以使用从00000000h到FFFFFFFFh的4GB范围之内的任何一个值。虽然每一个32位进程可使用4GB的地址空间,但并不意味着每一个进程实际拥有4GB的物理地址空间,该地址空间仅仅是一个虚拟地址空间。此虚拟地址空间只是内存地址的一个范围,进程实际可以得到的物理内存要远小于其虚拟地址空间。进程的虚拟地址空间是为每个进程所私有的,在进程内运行的线程对内存空间的访问都被限制在调用进程之内,而不能访问属于其他进程的内存空间(比如声明这是A进程的4GB,那是B进程的4GB)。这样,在不同的进程中可以使用相同地址的指针来指向属于各自调用进程的内容而不会由此引起混乱。
[img]http://img.zdnet.com.cn/1/765/liGS541OHroM.jpg[/img]
在Windows系统中,任何一个进程都会被赋予其自己的虚拟地址空间(虚拟内存),该虚拟地址空间可以覆盖了一个相当大的范围。对于一个32位进程,其可以拥有的地址空间为2^32=4GB,这使得一个指针可以使用从00000000h到FFFFFFFFh的4GB范围之内的任何一个值。虽然每一个32位进程可使用4GB的地址空间,但并不意味着每一个进程实际拥有4GB的物理地址空间,该地址空间仅仅是一个虚拟地址空间。此虚拟地址空间只是内存地址的一个范围,进程实际可以得到的物理内存要远小于其虚拟地址空间。进程的虚拟地址空间是为每个进程所私有的,在进程内运行的线程对内存空间的访问都被限制在调用进程之内,而不能访问属于其他进程的内存空间(比如声明这是A进程的4GB,那是B进程的4GB)。这样,在不同的进程中可以使用相同地址的指针来指向属于各自调用进程的内容而不会由此引起混乱。
读取物理内存
作者:admin 日期:2009-10-25
大家知道在windows NT中,如果已知虚拟地址可以通过进程页表或者内核提供的MmGetPhysicalAddress来取得对应的物理地址。现在我们反过来看一下,如果已知一个物理内存地 址 (假设地址有效),如何取得物理地址中的内容呢?经过一番思考后,我发现一个方法,但我这里先卖个关子,为什么呢?因为我觉得这个方法有些繁琐。经过和csdn的各位高手讨论之后,加上本人的一共总结出3种方法,现在想和大家分享一下,下面不再废话,立即进入正题 J[方法1]:使用内核提供的MmMapIoSpace函数原来内核早就提供了很简单的接口,就是MmMapIoSpace函数,不过在DDK文档中看到该函数的说明如下:PVOID MmMapIoSpace( IN PHYSICAL_ADDRESS PhysicalAddress, IN ULONG NumberOfBytes,IN MEMORY_CACHING_TYPE CacheType );它只有3个形参,这和实际Masm32v9.0声明的4个形参有所不同,为了确定,我通过 IDA 反汇编证实该函数确实有4个形参。经过测试,我猜测中间的ULONG NumberOfBytes参数实际由64位字节的(两个双字)高低两部分组成,即在Masm32v9.0中有:PVOID MmMapIoSpace( IN PHYSICAL_ADDRESS PhysicalAddress,IN ULONG NumberOfBytesHighPart,IN ULONG NumberOfBytesLowPart,IN MEMORY_CACHING_TYPE CacheType );这样的话调用就很简单了:invoke MmMapIoSpace,_phyaddr,0,4,MmNonCached若成功该函数返回影射后的虚拟地址,否则返回NULL。这样就可以间接达到读取物理地址中内容的第一个方法。但可能我对参数功能的猜测也有错误,如果有误请指出。不胜感谢。[方法2]:通过操作物理内存对象来完成到虚拟地址的影射简单的说这个方法的基本思想如下:a : 取得本进程句柄;b : 取得物理内存对象的句柄;c : 将物理内存地址影射到进程的虚拟地址空间中。下面是我从C改写后的汇编关键代码:;***************************************************************************GetValByPhyAddr proc uses esi edi ebx _phyaddr local hpmem:dword local hp:dword local dwsize:dword local dwbase:dword local dwret:dword local cid:CLIENT_ID local stLR:LARGE_INTEGER local ObjAttrsMem:OBJECT_ATTRIBUTES local ObjAttrsP:OBJECT_ATTRIBUTES mov dwbase,0 mov dwsize,4 push _phyaddr pop stLR.LowPart mov stLR.HighPart,0 invoke PsGetCurrentProcessId mov cid.UniqueProcess,eax mov cid.UniqueThread,0 invoke InitObjAttrs,addr ObjAttrsP,0 ;取得本进程句柄 Invoke ZwOpenProcess,addr hp,PROCESS_DUP_HANDLE,\ addr ObjAttrsP,addr cid invoke InitObjAttrs,addr ObjAttrsMem,addr devphymem ;取得物理对象的句柄 Invoke ZwOpenSection,addr hpmem,\ SECTION_MAP_READ or SECTION_MAP_WRITE,\ addr ObjAttrsMem ;将物理内存地址影射到进程的虚拟地址空间中 invoke ZwMapViewOfSection,hpmem,hp,addr dwbase,\ 0,4,addr stLR,addr dwsize,1,\ MEM_TOP_DOWN,PAGE_READWRITEmov edx,dwbase mov eax,[edx] ;取得影射后对应虚拟地址中的内容 mov dwret,eax ;释放资源 invoke ZwUnmapViewOfSection,hp,addr dwbase invoke ZwClose,hpmem invoke ZwClose,hp mov eax,dwret retGetValByPhyAddr endp;***************************************************************************[方法3]:关闭CPU分页机制达到直接读取物理地址的目的第3种方法就是我前面卖关子的方法 J ,这种方法不依赖于OS,了解保护模式的朋友都知道:进入保护模式后如果关闭分页机制则CPU就会将线形地址直接解释成物理地址。关闭分页很简单,只需3行汇编代码:mov eax,cr0and eax,7fffffffhmov cr0,eax打开分页同样很简单:mov eax,cr0or eax,80000000h mov cr0,eax既然这么简单,为什么我在前面说这个方法有些繁琐呢?原因之一是如果仅仅关闭分页就会使原来依赖于分页的windows变得一团糟,马上会发生著名的蓝屏现象,不爽哦!L那要怎么做呢?经过我的尝试,发现有3点非常重要:1 : 要保证windows处在较高的IRQL级别,防止关闭分页后 被打断;2 : 要将处理分页、读取物理地址的指令块放到线形地址等于 物理地址的页中;3 : 要做好数据的恢复工作。第1点和第3点都容易理解,可能有人会疑问第2点,为什么要放到线形地址等于物理地址的空间中呢?原因其实也很简单,就是一旦关闭分页,所有地址都将以物理地址来解释,如果先前的虚拟地址和物理地址不相同那么很可能就会发生执行错误指令流的问题。(当然也可以不相同,只要你能保证关分页后能执行正确指令即可。)那么如何将物理地址和虚拟地址设置为相同呢?我的方法是将虚拟地址对应地页表PTE中的物理页基址改为包容即可。我随机选择了一个虚拟地址 0x1c00000 ,为了简单它正好是页面的一个基址。下面我构造了它的PTE使得其中的物理也帧指向它:mov edx,0ffdf0000h mov eax,[edx] mov tmp0,eax ; 保存原始值 ;mov dword ptr [edx],1c00027h mov dword ptr [edx],1c00007h ;初始化PTE mov edx,0c03ff7c0h mov eax,[edx] and eax,0fffff000h or eax,7h mov edx,0c030001ch mov ebx,[edx] mov tmp1,ebx ; 保存原始值 mov dword ptr [edx],eax ;刷新TLB mov eax,cr3 mov cr3,eax 最后两句指令在我前一篇: <<Windows内核编程研究一:改变进程PTE>> 中有过说明,这里就不解释了。结束了PTE的设置后,下面就是将指令块拷贝到指定位置,代码如下:mov ecx,slenmov esi,subasmmov edi,1c00000hcldrep movsb而subasm指令块完成的就是实际设置分页和读取物理地址内容的工作,如下:subasm: mov eax,cr0 and eax,7fffffffh ;关闭分页机制 mov cr0,eax jmp SHORT PageCPageC: mov edx,[ecx]mov eax,cr0 or eax,80000000h ;打开分页机制 mov cr0,eax jmp SHORT PageOPageO: jmp edislen = $ - subasm借用一句话作为结尾“…一切都那么清楚明白,然而却无法透彻理解。理解就是改变,就是超越自己已有的认识。”
关于ring3到ring0的代码实现
作者:admin 日期:2009-10-22
调试权限(debug权限)
作者:admin 日期:2009-10-21
windows启动以及exe文件的加载简介
作者:admin 日期:2009-10-14
先来看这样一个过程(非VISTA启动):CPU复位->传统BIOS->MBR->引导扇区->NTLDR->NTOS->SMSS->1:CSRSS 2:WinLogon->1:LSRSS 2:Services 3:LogonUI->2:Services->Svchost 3:LogonUI->USERINT->1:StartUp App 2:Shell
这是非 VISTA 的启动过程,是传统 Windows 的启动,这里有几处必要提到,首先 NTLDR 是一个非常重要的启动文件,在 C 盘下,相关的还有 boot.ini, pagefile.sys, NTDETECT.COM,我们按 F8 或者 F5 时进入安全模式的界面也是它产生的。然后是 NTOSKEL 这就是产生滚动条界面的,这是启动最漫长的过程!我曾经看到过有“高手”说过可以改掉滚动条滚动次数的注册表位置,其实这是不能改的,在这个界面下的过程非常漫长非常复杂,不提。然后是 SMSS 进程,这是第一个真正意义上由 .EXE 产生的进程。然后建出 CSRSS 子系统服务器进程和 WinLogon 进程。最后建出 Shell:Explorer.exe 进程。和本文最相关的就是这个 Shell 了,Shell “命令解释器”它的经典就是 Explorer.exe 。每一个窗口其实就是它创建的一个线程!这是一个非常厉害的多线程设计了!比如我们点击桌面上的图标启动一个程序,就是由它来加载创建的,好了,有了这些就开始来讲本文的其中一个内容:.EXE 的加载过程,然后再由此扩充开。
双击一个 .EXE 图标(操作系统怎么定位哪一个图标不是本文的内容),Shell 调用 CreateProcess 函数,系统找出在调用 CreateProcess 函数时的 .exe 文件,如果文件不在则返回 FALSE 进程创建失败。成功的话则为该进程创建一个新进程内核对象,这个内核对象是由系统内核管理的,关于内核对象也是一个很长的话题,详细叙述的话我写到明天恐怕都写不完这篇文章了,只要知道这个时候如果 CreateProcess 成功的话系统为这个进程创建了一个使用记数为1的进程内核对象,值得一提的是有一个进程内核对象句柄表,这里纪录了所有在该进程中所有创建出来的进程内核对象,但这个东西 Microsoft 没有提供相关文档,我的偶像 Jeffrey Richter 也只是简单的提了一提,接下来系统为这个新进程创建了一个私有地址空间,这就是我们很清楚的 4GB 地址空间! 写到这里先停住,我发现了一个比较大的问题,Shell 调用 CreateProcess 这个函数时其中的参数是哪里来的?我根据 Jeffrey Richter 的一句话也就是系统找出 EXE 文件,如果存在的话则创建成功,那么我进一步推论,那其中的参数很有可能是来自 PE 格式中的信息,可以继续推论下去,研究一下 CreateProcess 的参数再对照一下 PE 格式各个段的包含信息,那应该可以研究出某些东西来,这个细节我是还没有深入对比过,如果有哪位看官知道的话还请赐教!在这里先谢过了!接下来系统会保留一个足够大的区域来存放.exe 文件,默认的话是保存在从OXOO4OOOOO开始的位置,而这个数值是在 exe 这个 PE 结构中的信息,用 /BASE 是可以改的。这里就牵涉到内存映射文件了,不提。我们来研究一下 0X00400000 在内存中的什么区域,看一下 Win32 内存结构中4GB的划分(不再提 98 那破烂了)0x00000000 - 0x0000FFFF 这64KB用于 NULL 指针分配,举一个 Richter 的例子:int *pnSomeInteger = (int*)malloc(sizeof(int)); *pnSomeInteger = 5; 如果 malloc 不能找到足够的内存来分配的话那它就返回 NULL 就是保存在这里了,接下来 0x00010000 - 0x7FFEFFFF 这一段就是 Win32 进程私有的地址空间,刚才的.exe 加载就在这一段空间中,接下来继续加载程序执行所必须的 DLL 文件也是在这个段里,当然在这里还有一些数据需要加载,和为线程开辟的堆栈区,所以进程的这个用户区其实分成了3个部分:文本区包括指令和可读的数据,通常这个段是标记为可读,数据区,这个段对应 PE 中的 DATA_BASS 包含以初始化和未初始化的数据,静态变量也存放在这个区中,最后就是堆栈区,这是为线程分配的默认为1MB,当然是可以改的,在这里包含了函数参数和局部变量,当然也有现场保护时的信息,很关键的一点是 IP 指针也在这里,缓冲区溢出攻击就是在这个区域做文章,俗称:践踏堆栈。好!因为 Win32 中进程是一个惰性的,它什么也不执行,除了 EXE 和 DLL 还有它们所需的数据加载到进程地址空间外每个进程还拥有别的资源,这里只要记住:窗口和钩子是属于线程的外其他都是进程的,所以进程必须有一个线程来执行它的代码,这时候系统就为进程创建一个主线程,但它是调用 C 运行时库函数,这里又有区分 CUI 和 GUI,ANSI 和 UNIODE 的差别,如果以 GUI 和 UNICODE 来讲,它调用的是 wWinMainCTRStartup 这个可执行文件的启动函数。这个函数的功能不多讲,它会进行一系列初始化工作,完了后它将调用我们编写的主函数入口函数比如 wWinMain();最后 exit 调用调用操作系统的ExitProcess 函数,将 nMainRetVal 传递给它,这使得操作系统能够撤销进程并设置它的 exit 代码。到这里启动过程结束!
这是非 VISTA 的启动过程,是传统 Windows 的启动,这里有几处必要提到,首先 NTLDR 是一个非常重要的启动文件,在 C 盘下,相关的还有 boot.ini, pagefile.sys, NTDETECT.COM,我们按 F8 或者 F5 时进入安全模式的界面也是它产生的。然后是 NTOSKEL 这就是产生滚动条界面的,这是启动最漫长的过程!我曾经看到过有“高手”说过可以改掉滚动条滚动次数的注册表位置,其实这是不能改的,在这个界面下的过程非常漫长非常复杂,不提。然后是 SMSS 进程,这是第一个真正意义上由 .EXE 产生的进程。然后建出 CSRSS 子系统服务器进程和 WinLogon 进程。最后建出 Shell:Explorer.exe 进程。和本文最相关的就是这个 Shell 了,Shell “命令解释器”它的经典就是 Explorer.exe 。每一个窗口其实就是它创建的一个线程!这是一个非常厉害的多线程设计了!比如我们点击桌面上的图标启动一个程序,就是由它来加载创建的,好了,有了这些就开始来讲本文的其中一个内容:.EXE 的加载过程,然后再由此扩充开。
双击一个 .EXE 图标(操作系统怎么定位哪一个图标不是本文的内容),Shell 调用 CreateProcess 函数,系统找出在调用 CreateProcess 函数时的 .exe 文件,如果文件不在则返回 FALSE 进程创建失败。成功的话则为该进程创建一个新进程内核对象,这个内核对象是由系统内核管理的,关于内核对象也是一个很长的话题,详细叙述的话我写到明天恐怕都写不完这篇文章了,只要知道这个时候如果 CreateProcess 成功的话系统为这个进程创建了一个使用记数为1的进程内核对象,值得一提的是有一个进程内核对象句柄表,这里纪录了所有在该进程中所有创建出来的进程内核对象,但这个东西 Microsoft 没有提供相关文档,我的偶像 Jeffrey Richter 也只是简单的提了一提,接下来系统为这个新进程创建了一个私有地址空间,这就是我们很清楚的 4GB 地址空间! 写到这里先停住,我发现了一个比较大的问题,Shell 调用 CreateProcess 这个函数时其中的参数是哪里来的?我根据 Jeffrey Richter 的一句话也就是系统找出 EXE 文件,如果存在的话则创建成功,那么我进一步推论,那其中的参数很有可能是来自 PE 格式中的信息,可以继续推论下去,研究一下 CreateProcess 的参数再对照一下 PE 格式各个段的包含信息,那应该可以研究出某些东西来,这个细节我是还没有深入对比过,如果有哪位看官知道的话还请赐教!在这里先谢过了!接下来系统会保留一个足够大的区域来存放.exe 文件,默认的话是保存在从OXOO4OOOOO开始的位置,而这个数值是在 exe 这个 PE 结构中的信息,用 /BASE 是可以改的。这里就牵涉到内存映射文件了,不提。我们来研究一下 0X00400000 在内存中的什么区域,看一下 Win32 内存结构中4GB的划分(不再提 98 那破烂了)0x00000000 - 0x0000FFFF 这64KB用于 NULL 指针分配,举一个 Richter 的例子:int *pnSomeInteger = (int*)malloc(sizeof(int)); *pnSomeInteger = 5; 如果 malloc 不能找到足够的内存来分配的话那它就返回 NULL 就是保存在这里了,接下来 0x00010000 - 0x7FFEFFFF 这一段就是 Win32 进程私有的地址空间,刚才的.exe 加载就在这一段空间中,接下来继续加载程序执行所必须的 DLL 文件也是在这个段里,当然在这里还有一些数据需要加载,和为线程开辟的堆栈区,所以进程的这个用户区其实分成了3个部分:文本区包括指令和可读的数据,通常这个段是标记为可读,数据区,这个段对应 PE 中的 DATA_BASS 包含以初始化和未初始化的数据,静态变量也存放在这个区中,最后就是堆栈区,这是为线程分配的默认为1MB,当然是可以改的,在这里包含了函数参数和局部变量,当然也有现场保护时的信息,很关键的一点是 IP 指针也在这里,缓冲区溢出攻击就是在这个区域做文章,俗称:践踏堆栈。好!因为 Win32 中进程是一个惰性的,它什么也不执行,除了 EXE 和 DLL 还有它们所需的数据加载到进程地址空间外每个进程还拥有别的资源,这里只要记住:窗口和钩子是属于线程的外其他都是进程的,所以进程必须有一个线程来执行它的代码,这时候系统就为进程创建一个主线程,但它是调用 C 运行时库函数,这里又有区分 CUI 和 GUI,ANSI 和 UNIODE 的差别,如果以 GUI 和 UNICODE 来讲,它调用的是 wWinMainCTRStartup 这个可执行文件的启动函数。这个函数的功能不多讲,它会进行一系列初始化工作,完了后它将调用我们编写的主函数入口函数比如 wWinMain();最后 exit 调用调用操作系统的ExitProcess 函数,将 nMainRetVal 传递给它,这使得操作系统能够撤销进程并设置它的 exit 代码。到这里启动过程结束!
调试工具debug的用法
作者:admin 日期:2009-10-13
有不少朋友来信问过我这样一个问题: 怎样才能成为一名优秀的HACKER。我的回答是: 深入的了解汇编知识,学好DEBUG的用法。这次借Pc life的一角之地,我将详细的讲解一下DEBUG的用法。
DEBUG是一个DOS实用程序,是供程序员使用的程序调试工具,可以用它检查内存中任何地方的字节以及修改任何地方的字节.它可以用于逐指令执行某个程序以验证程序运行的正确性,也可以追踪执行过程、比较一个指令执行前后的值以及比较与移动内存中数据的范围,读写文件与磁盘扇区。
DEBUG把所有数据都作为字节序列处理。因此它可以读任何类型的文件。DEBUG可以识别两种数据: 十六进制数据和ASCⅡ码字符。它的显示格式是各个字节的十六进制值以及值在32与126之间的字节的相应ASCⅡ码字符。
在DEBUG中输入数据有两种方法: 提示方法和非提示方法。在用提示方法时,用户可以输入要求输入数据的命令,后跟数据所要输入的地址。然后用户就可以看到该地之中已有内容及一个冒号提示符。此时用户可以在提示符下输入一个新的值或者按下回车键或CTRL+C回到短横(-)提示符。在运用非提示方法时,用户可以输入要输入数据的内存地址以及要输入的字节。但与使用字处理程序或正文编辑程序时不一样,在使用DEBUG时,用户不能直接移动光标到一入口点输入或修改数据,而要一次输入一个或几个字节。
在使用DEBUG时可以只涉及内存中的数据,从而一般都要指定所要处理的内存地址,地址的输入格式是: [段地址]: [位移]。如果没有输入地址,DEBUG将假定为当前内存段,从位于地址100H的字节开始。前100H字节保留给程序段前缀使用,这一专用区域用于建立DOS与程序之间的联系。DEBUG总是用四位十六进制数表示地址。用两位数表示十六进制数据。
DEBUG是一个DOS实用程序,是供程序员使用的程序调试工具,可以用它检查内存中任何地方的字节以及修改任何地方的字节.它可以用于逐指令执行某个程序以验证程序运行的正确性,也可以追踪执行过程、比较一个指令执行前后的值以及比较与移动内存中数据的范围,读写文件与磁盘扇区。
DEBUG把所有数据都作为字节序列处理。因此它可以读任何类型的文件。DEBUG可以识别两种数据: 十六进制数据和ASCⅡ码字符。它的显示格式是各个字节的十六进制值以及值在32与126之间的字节的相应ASCⅡ码字符。
在DEBUG中输入数据有两种方法: 提示方法和非提示方法。在用提示方法时,用户可以输入要求输入数据的命令,后跟数据所要输入的地址。然后用户就可以看到该地之中已有内容及一个冒号提示符。此时用户可以在提示符下输入一个新的值或者按下回车键或CTRL+C回到短横(-)提示符。在运用非提示方法时,用户可以输入要输入数据的内存地址以及要输入的字节。但与使用字处理程序或正文编辑程序时不一样,在使用DEBUG时,用户不能直接移动光标到一入口点输入或修改数据,而要一次输入一个或几个字节。
在使用DEBUG时可以只涉及内存中的数据,从而一般都要指定所要处理的内存地址,地址的输入格式是: [段地址]: [位移]。如果没有输入地址,DEBUG将假定为当前内存段,从位于地址100H的字节开始。前100H字节保留给程序段前缀使用,这一专用区域用于建立DOS与程序之间的联系。DEBUG总是用四位十六进制数表示地址。用两位数表示十六进制数据。