如何手工windbg 抓取dumpp文件

使用DEBUGDIAG手动抓取DUMP文件 - You are really something! - 51Testing软件测试网 51Testing软件测试网-中国软件测试人的精神家园
使用DEBUGDIAG手动抓取DUMP文件
& 14:35:09
/ 个人分类:
DebugDiagdumplIIS dumpldumpldumpldump手动抓取IIS dump文件DebugDiag 1.1 (x86)Processesw3wpCreate Full Userdumpdumpdump查看dump文件的默认存储位置DebugDiag 1.1 (x86)&&&&&&&&&&&&&&&&&&miscdump&&&&&&修改dump文件的存储位置DebugDiag 1.1 (x86)Tools-&Options and SettingsManual Userdump Save Folder&抓取dump文件的时机dumpIISPrvite#time in GCdumpgen2large object heapbytes in all heapsdumpdumpProcdump是一个轻量级的Sysinternal团队开发的命令行工具, 它的主要目的是监控应用程序的CPU异常动向, 并在此异常时生成crash dump文件, 供研发人员和管理员确定问题发生的原因. 你还可以把它作为生成dump的工具使用在其他的脚本中.&有了它, 就完全不需要在同一台服务器上使用诸如32位系统上的Debug Diag 1.1或是64位系统上的ADPlus了.&问题描述===============在任务管理器里发现w3wp.exe的CPU总在49%-60%左右, 间歇性地会下降一些. 我们需要在w3wp.exe的CPU在50%以上并能维持三秒钟的情形下抓取两组dump. 如果使用debug diag或adplus的话, 会比较困难, 因为这需要等待时机并手动抓取. 容易出现抓到的dump里不包含那些引发异常的动作的情况.&解决方案 - 救世主procdump===============Procdump可以很方便地帮助我们应付这种情况, 加速动作过程, 抓取正确数据集合. 它会指定的时间内监控目标进程的cpu, 并在那个点抓取一个内存快照(dump).比如说:procdump -ma -c 50 -s 3 -n 2 5844 (Process Name or PID)&&-0 c:\dumpfile&&& -ma&生成full dump, 即包括进程的所有内存. 默认的dump格式包括线程和句柄信息.&&& -c&在CPU使用率到达这个阀值的时候, 生成dump文件.&&& -s&CPU阀值必须持续多少秒才抓取dump文件.&&& -n&在该工具退出之前要抓取多少个dump文件.&& &-o&dump文件保存目录.&&上面的命令行会监控w3wp.exe的CPU, 在CPU使用率超过百分之五十超过3秒的时候, 生成dump文件, 重复该动作两次.&下面是该命令的一个实例记录:C:\Users\jaskis\Downloads\procdump&&procdump -ma -c 50 -s 3 -n 2 5844 -o c:\dumpfileProcDump v1.1 - Writes process dump files&Copyright (C) 2009 Mark Russinovich&Sysinternals -&Process:&&&&&&&&&&& w3wp.exe (5844)&CPU threshold:&&&&& 50% of systemDuration threshold: 3sNumber of dumps:&&& 2Hung window check:& Disabled&Exception monitor:& Disabled&Dump file:&&&&&&&&& C:\Users\jaskis\Downloads\procdump\w3wp.dmp&Time&&&&&&& CPU& Duration&[23:48.35]& 59%& 1s&[23:48.36]&CPU usage below threshold.[23:48.37]&&54%& 1s[23:48.38]& 55%& 2s[23:48.39]&&61%& 3sProcess has hit spike threshold.Writing dump file C:\Users\jaskis\Downloads\procdump\w3wp_839PM.dmp... Dump written.&[23:48.44]&&61%& 1s[23:48.45]&&59%& 2s&[23:48.46]&&57%& 3s&Process has hit spike threshold.&Writing dump file C:\Users\jaskis\Downloads\procdump\w3wp_846PM.dmp...&Dump written.&下载路径:ProcDump v3.01&&译自:Using ProcDump.exe to monitor w3wp.exe for CPU spikes
阅读(...) 评论()博客访问:
博文数量: 5145
注册时间:
认证徽章:
Oracle & MySQL DBA, EBS DBA,希望在这里一起分享知识,讨论技术,畅谈人生 。
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Linux
&&&环境:&&& JDK 1.5/1.6, WebLogic 9.0 or later当服务器挂起,崩溃或者性能很差时,可以抓取服务器的线程堆栈(Thread Dump)用于后续的分析.Thread dump提供了当前活动的线程的快照. 它提供了JVM中所有Java线程的栈跟踪信息,有很多方式可用于获取Thread Dump。 操作系统命令获取ThreadDump:Windows:a. 转向服务器的标准输出窗口并按下Control + Break组合键, 之后需要将线程堆栈复制到文件中UNIX/ Linux首先查找到服务器的进程号(process id), 然后获取堆栈.a.&&&&& ps –ef& | grep javab.&&&&& kill& -3 -------------------------------------------& JVM 自带的工具获取线程堆栈:JDK自带命令行工具获取PID并做ThreadDump:a.&& jpsb.&& jstack && 使用JVisualVM: Threads 标签页ThreadDump按钮.-------------------------------------------& WebLogic 自带的获取 thread dump的工具:1. 使用 Admin Console a. 登录 Admin Console , 点击对应的服务器b. 点击Server Monitoring Threadsc. 点击: Dump Thread Stack 按钮 2. 使用WLST (WebLogic Scripting Tool) java& weblogic.WLST connect('weblogic','weblogic123','t3://dggtsebs01-vlx:7010')cd('Servers')cd('soa_server1')threadDump()disconnect()exit()注意: 线程堆栈将会保存在运行wlst的当前目录下.
阅读(9306) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。博客访问: 1150555
博文数量: 323
博客积分: 10653
博客等级: 上将
技术积分: 3198
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: 网络与安全
大家好,其实是前几天写简历的时候写了自己能手动脱壳,(手动脱壳,从寻找OEP->dump->IAT修复,最后成功拆除)然而在脱壳方面的文章,一直没时间写,因为本来打算写逆向C++的,但是c++的内容绝不是三几句话能包含的,我打算自己整理好以后会一并发出来;还忘大家谅解;&由于前不久瑞星电话面试的时候问我是不是能手动脱壳,遇到不熟悉的壳怎么办,答:&OEP-》DUMP—》IAT修复,最后问了找OEP的方法,为了证明下自己能做这个事,所以打算写篇脱壳的文章;当然也是为了学习。技术方面的东西,我是报着学习的态度面对的;因为我知道我还是只小菜;&嘿嘿。。。废话不说;开始:1:PE文件的装载我们知道,一个普通的PE文件存放在磁盘中,在你不点击它之前,它其实和你电脑里的一张图片一样,形象的说来,它成了个摆设,当鼠标双击它之后,shell调用CreateProcess函数打开一个有效的windows可执行文件,并且创建了一个内存区对象,为的是稍后将它映射到内存空间中;然后通过调用WIndows的内部函数NtCreateProcess函数,创建了一个windows执行体对象,以运行该映像;而创建执行体对象涉及以下几步(由创建线程来完成的):1)&建立EPROCESS块2)创建初始的进程地址空间3)初始化内核进程块(KPROCESS)4)结束地址空间的创建过程5)建立PEB6)完成执行体对象的创建过程&由于,本文写的是脱壳,更多详细,请参考&Windows.Internals.Fourth.EditionPE文件装载过程:(Undocumented&Windows)我们来看一下&loader&是如何解释&PE&文件,又是如何为执行准备内存&image&的。&loader&需要找到空闲的虚拟地址空间来将文件映射到内存。&loader&尝试着将&image&加载在&preferred&base&address。成功后,loader&将&sections&映射入内存。loader&扫描&section&table,用每一个&section&的&RVA&加上基地址算出&section&的加载地址,然后将&sections&加载在相应的地址上。页属性是根据&section&的特征要求设定的。将&section&映射入内存后,若基地址不等于&preferred&base&address,则&loader&开始进行基址重定位。之后检查&import&table&并加载所需的&DLLs。加载&DLL&与加载可执行文件的过程一样——映射&sections,基址重定位,解析&imports等等。所有的&DLL&都加载了之后,就修改&IAT&使之指向实际的&imported&函数的地址。成了!&image&已准备好执行了。关于Load的文章,What&Goes&On&Inside&Windows&2000:&Solving&the&Mysteries&of&the&Loader&我放附件里,由于时间爱你关系,只翻译了一小点,大家凑合看吧;2&:壳以及壳的加载过程:1)什么是壳?&&&&我们可以把壳看成一个子程序,由它处理后的Pe文件在磁盘中一般是以加密后的形式存在的,有的壳还带有压缩功能,使得exe文件更加小巧,加壳在一定程度上可以防止破解者对程序文件的非法修改,同时可以防止程序被反编译;壳附加在原程序上通过Load载入内存后,却抢先于原程序执行,也就是在PE文件代码段执行之前抢先得到控制权;&然后在执行过程中对原PE文件加密,还原,还原后在把控制权交还给原程序;2)壳的加载过程&a:保存入口参数,加壳程序初始化时保存各寄存器的值,其实对windows来说,在每个子程序执行之前,总要保存ebx,edi,esi,ebp寄存器的值,而ecx,edx的值是不固定的,不能在返回时应用。特别注意:从&Windows&API&函数中返回后,eax,ecx,edx&中的值和调用前不一定相同。当函数返回时,返回值放在eax中。如果您应用程序中的函数提供给&Windows&调用时,也必须尊守这一点,即在函数入口处保存段寄存器和&ebx,esp,esi,edi&的值并在函数返回时恢复。如果不这样一来的话,您的应用程序很快会崩溃。而通常,我们都用pushad/popad&&pushfd/popfd指令保存和恢复现场环境,注意:上面说过,壳可以看成一子程序,它只是比没加壳的代码提前获得了控制权,所以基本在没一个壳的开头,总能看到这个指令:&>&&60&&&&&&&&&&&&&&pushad&&&&b:处理多次进入c:模拟PE加载器完成相应的功能,处理完后将控制权交还给原程序;将控制权交给程序原入口点就是大家熟悉的(OEP)了;&在这一步中,还包括对输入表的处理,重定位表的处理,等;&由于加密加密三书上写的很详细,所以不在重复;关于壳的加载过程,网上有篇文章:&我转在我的blog上,有兴趣的可以看看;3:手动脱壳三部曲1)&&查找程序的真正入口(oep)2)&&抓取内存映像文件(dump)3)&&Pe文件重建到这里,我们可以开始练手了,注意:&不要在不熟悉pe文件格式的情况下,就想着手动脱壳,至少不要在还没搞清楚导入表和导出表,重定位表的情况下就想着更进一步,如果这样,无疑,你是在自找苦吃;我用的加密解密三的例子:RebPe.exe好了废话不说,开始三部曲第一部:&寻找OEP这一部分涉及几种下断的方法和原理,如果不清楚的,赶紧翻开加密解密三,第二章,看吧,最近在看深入浅出MFC,记住一句话:勿在浮沙上筑高台;寻找OEP的几种方法:要是你对壳很熟悉,你当然可以一条指令一条指令的来,一直跟踪到代码段,兄弟我除了佩服你的技术精湛之余,还有向你学习的冲动;&但是,我们还是来用用书上的剩下的一些方法看看;1:内存二次访问断点找OEP&&&原理:外壳首先要将原来压缩的代码解压,并放到对应的区块上,处理完毕,将跳到代码段执行。这种方法的关键,要等到代码段解压完毕,再对代码段设置内存访问断点,而一般的壳,会依次对.code&.data&.rsrc区块进行解压处理,所以,可以现在非代码段上下内存访问断点,此时代码段已经解压,在对代码段设内存访问断点;操作如下:a:)OD载入RebPe.exe&看到代码如下:&>&&60&&&&&&&&&&&&&&pushad&&&&E8&C2000000&&&&&call&&&&&&&&2E:3001&&&&&&&&&xor&&&&&byte&ptr&cs:[ecx],&al&&&&0000&&&&&&&&&&&&add&&&&&byte&ptr&[eax],&al0041300B&&&&0000&&&&&&&&&&&&add&&&&&byte&ptr&[eax],&al0041300D&&&&0000&&&&&&&&&&&&add&&&&&byte&ptr&[eax],&al0041300F&&&&0000&&&&&&&&&&&&add&&&&&byte&ptr&[eax],&al&&&&003E&&&&&&&&&&&&add&&&&&byte&ptr&[esi],&bh&&&&3001&&&&&&&&&&&&xor&&&&&byte&ptr&[ecx],&al&&&&002E&&&&&&&&&&&&add&&&&&byte&ptr&[esi],&chb:)Alt+M&打开内存窗口,对rdata设内存访问断点&:&F2(,你也可以对其它的非代码段设断;)F9运行,暂停在:&&&&A4&&&&&&&&&&&&&&movs&&&&byte&ptr&es:[edi],&byte&ptr&[esi>&&&&B3&02&&&&&&&&&&&mov&&&&&bl,&2&&&&E8&6D000000&&&&&call&&&&004131BA0041314D&&^&73&F6&&&&&&&&&&&jnb&&&&&short&在Alt+M&,对.Text设断&F2后,F9003A0282&&&&61&&&&&&&&&&&&&&popad003A0283&&&&68&&&&&&push&&&&401130&&&&&&;&OEP嘿嘿,看到了吧;003A0288&&&&C3&&&&&&&&&&&&&&retn003A0289&&&&3011&&&&&&&&&&&&xor&&&&&byte&ptr&[ecx],&dl我们跟踪,会发现,指令可读性较差,不用担心:&ctrl&+a&,OD会帮你:&此时,来到如下;也就是我们Pe的真正入口处了:&&/.&&55&&&&&&&&&&&&push&&&&ebp&&|.&&8BEC&&&&&&&&&&mov&&&&&ebp,&esp&&|.&&6A&FF&&&&&&&&&push&&&&-1&&|.&&68&B8504000&&&push&&&&0040113A&&|.&&68&FC1D4000&&&push&&&&00401DFC&&&&&&&&&&&&&&&&&&&&&&&&&;&&SE&处理程序安装0040113F&&|.&&64:A1&0000000>mov&&&&&eax,&dword&ptr&fs:[0]&&|.&&50&&&&&&&&&&&&push&&&&eax&&|.&&64:>mov&&&&&dword&ptr&fs:[0],&esp0040114D&&|.&&83EC&58&&&&&&&sub&&&&&esp,&58&&|.&&53&&&&&&&&&&&&push&&&&ebx&&|.&&56&&&&&&&&&&&&push&&&&esi&&|.&&57&&&&&&&&&&&&push&&&&edi&&|.&&8965&E8&&&&&&&mov&&&&&dword&ptr&[ebp-18],&esp&&|.&&FF15&&call&&&&dword&ptr&[405028]&&&&&&&&&&&&&&&;&&kernel32.GetVersion&&&&&&&&&&&&&&&&&&&&;这个函数熟悉吧0040115C&&|.&&33D2&&&&&&&&&&xor&&&&&edx,&edx随便用PE查看器,看下入口点:&&–&&=&1130&&(入口RVA)&2:堆栈平衡原理找oep&我们说过,在windows中调用子程序前,必须保存现场环境,而当子程序调用之前,必须恢复现场;&这一部分,可能你要,至少要对堆栈有个基本的了解,你可以参考我前面写的逆向C++中,函数,那一节,有一小部分介绍;而要继续深入,推荐arhat的&the&shellcode&handbook&一书。我们知道,PUSHAD(Push&All&32-bit&General&Registers)指令格式:PUSHAD       ;80386+其功能是把寄存器EAX、ECX、EDX、EBX、ESP、EBP、ESI和EDI等压栈。POPAD(Pop&All&32-bit&General&Registers)指令格式:POPAD      ;80386+其功能是依次把寄存器EDI、ESI、EBP、ESP、EBX、EDX、ECX和EAX等弹出栈,它与PUSHAD对称使用即可。我们看看堆栈的变化:Popad未执行前:&&0012FFC4&&&7C817067&&返回到&kernel32.7C817067&;&当前esp指向0012FFC8&&&0012BBC40012FFCC&&&73FB49E40012FFD0&&&7FFD80000012FFD4&&&执行后:0012FFA4&&&0012BBC4&&&&;edi0012FFA8&&&73FB49E4&&&&;esi0012FFAC&&&0012FFF0&&&&;ebp0012FFB0&&&0012FFC4&&&&;esp0012FFB4&&&7FFD8000&&&&;ebx0012FFB8&&&7C92E4F4&&ntdll.KiFastSystemCallRet&&&;edx0012FFBC&&&0012FFB0&&&&&;ecx0012FFC0&&&&&&&&;eax0012FFC4&&&7C817067&&返回到&kernel32.7C817067对0012FFA4下硬件断点:&hr&0012FFA4F9&,程序中断在:003A0282&&&&61&&&&&&&&&&&&&&popad003A0283&&&&68&&&&&&push&&&&401130&&;熟悉吧,OEP003A0288&&&&C3&&&&&&&&&&&&&&retn&&其实堆栈平衡原理,是找第一个pushad&配对的popad,因为,在很多壳中,可能在处理数据的时候,还会调用其它子程序,这样,如果用观察法找配对&pushad&和popad指令就会让初学者,眼花缭乱,相信我,我有过这种经历;所以,用一个硬件断点,方便了很多吧;脱壳二部曲:&dump&抓取内存映像如果用OD里的dump插件,哈哈,那么IAT你都不用修复拉;&OD真的很好用,偶喜欢;好期待有天我也能弄个这NX的插件出来,奉献给大家;不过,有什么用呢;&大牛们都写好了摆好了;&你会发现,脱壳后运行的程序,运行的非常好;在这里,有一点补充下,有可能你加壳后,会发现文件执行的时候有错误;kanxue补充如下:将记事本和计算器&中Directory&Table&中的LoadConfig值清零,即可加。外壳程序处理时没有考虑LoadConfig。下面用loadPE来:&右键—》完全转存;&dump.Exe&双击,55555.。。。&不能用了吧;&笑不出来了吧;没关系,今天宿舍就停电了,本来打算连IAT修复也写完的,555.。。。我不想在宿舍住拉,每次干得兴起就断电;&那就明天在来吧;今天先到这;IAT修复:1:)先来回顾下基础知识:&&首先,PE文件中的数据按照装入内存后的页面属性被分成多个节,并由节表中的数据来描述这些节;一个节中的数据仅仅是属性相同而已,并不一定是同一种用途;&&其次,由于不同用途的数据可能被放在同一个节中,仅仅靠节表是无法确定它的存放的位置的,PE文件中依靠可选头中的数据目录表来指出它们的位置;结构如下:typedef&struct&_IMAGE_OPTIONAL_HEADER&{&&&&&//&&&&&//标准域&&&&&&//&&&&&USHORT&&M&&&&&&&&&&&&&&&&&&&//魔数&&&&&UCHAR&&&MajorLinkerV&&&&&&//链接器主版本号&&&&&UCHAR&&&MinorLinkerV&&&&&&//链接器小版本号&&&&&ULONG&&&SizeOfC&&&&&&&&&&&&&&//代码大小&&&&&ULONG&&&SizeOfInitializedD&&&//已初始化数据大小&&&&&ULONG&&&SizeOfUninitializedD&//未初始化数据大小&&&&&&ULONG&&&AddressOfEntryP&&&&&//入口点地址&&&&&ULONG&&&BaseOfC&&&&&&&&&&&&&&//代码基址&&&&&ULONG&&&BaseOfD&&&&&&&&&&&&&&//数据基址&&&&&//&&&&&//NT增加的域&&&&&//&&&&&ULONG&&&ImageB&&&&&&&&&&&&&&&&&&//映像文件基址&&&&&ULONG&&&SectionA&&&&&&&&&&&//节对齐&&&&&ULONG&&&FileA&&&&&&&&&&&&&&//文件对齐&&&&&USHORT&&MajorOperatingSystemV//操作系统主版本号&&&&&USHORT&&MinorOperatingSystemV//操作系统小版本号&&&&&USHORT&&MajorImageV&&&&&&&&&&//映像文件主版本号&&&&&USHORT&&MinorImageV&&&&&&&&&&//映像文件小版本号&&&&&USHORT&&MajorSubsystemV&&&&&&//子系统主版本号&&&&&USHORT&&MinorSubsystemV&&&&&&//子系统小版本号&&&&&ULONG&&&Reserved1;&&&&&&&&&&&&&&&&&&//保留项1&&&&&ULONG&&&SizeOfI&&&&&&&&&&&&&&&&//映像文件大小&&&&&ULONG&&&SizeOfH&&&&&&&&&&&&&&//所有头的大小&&&&&ULONG&&&CheckS&&&&&&&&&&&&&&&&&&&//校验和&&&&&USHORT&&S&&&&&&&&&&&&&&&&&&//子系统&&&&&USHORT&&DllC&&&&&&&&&//DLL特性&&&&&ULONG&&&SizeOfStackR&&&&&&&&&//保留栈的大小&&&&&ULONG&&&SizeOfStackC&&&&&&&&&&//指定栈的大小&&&&&ULONG&&&SizeOfHeapR&&&&&&&&&&//保留堆的大小&&&&&ULONG&&&SizeOfHeapC&&&&&&&&&&&//指定堆的大小&&&&&ULONG&&&LoaderF&&&&&&&&&&&&&&&&//加载器标志&&&&&ULONG&&&NumberOfRvaAndS&&&&&&&&//RVA的数量和大小&&&&&IMAGE_DATA_DIRECTORY&DataDirectory&&[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];&&&//数据目录数组&}&IMAGE_OPTIONAL_HEADER,&*PIMAGE_OPTIONAL_HEADER;typedef&struct&_IMAGE_DATA_DIRECTORY&{&&&&&ULONG&&&VirtualA&&&&&&&//虚拟地址&&&&&ULONG&&&S&&&&&&&&&&&&&&&&&//大小&}&IMAGE_DATA_DIRECTORY,&*PIMAGE_DATA_DIRECTORY//&各个目录项&//&输出目录&#define&IMAGE_DIRECTORY_ENTRY_EXPORT&&&&&&&&&0&//&输入目录&#define&IMAGE_DIRECTORY_ENTRY_IMPORT&&&&&&&&&1&//&资源目录&#define&IMAGE_DIRECTORY_ENTRY_RESOURCE&&&&&&&2&//&异常目录&#define&IMAGE_DIRECTORY_ENTRY_EXCEPTION&&&&&&3&//&安全目录&#define&IMAGE_DIRECTORY_ENTRY_SECURITY&&&&&&&4&//&基址重定位表&#define&IMAGE_DIRECTORY_ENTRY_BASERELOC&&&&&&5&//&调试目录&#define&IMAGE_DIRECTORY_ENTRY_DEBUG&&&&&&&&&&6&//&描述字符串&#define&IMAGE_DIRECTORY_ENTRY_COPYRIGHT&&&&&&7&//&机器值(MIPS&GP)&#define&IMAGE_DIRECTORY_ENTRY_GLOBALPTR&&&&&&8&//&TLS(线程本地存储)⑥目录&#define&IMAGE_DIRECTORY_ENTRY_TLS&&&&&&&&&&&&9&//&载入配置目录&#define&IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG&&&&10我们知道,从数据目录表引出的,仅仅是这些数据的RVA和数据块的尺寸,很明显,不同数据块的数据组织方式是不同的,比如导入表和导出表,描述它们的数据结构是不同的;如下:&typedef&struct&_IMAGE_EXPORT_DIRECTORY&{&&&&&ULONG&&&C&&&&&&&&&&&&//特征&&&&&ULONG&&&TimeDateS&&&&&&&&&&&&&&//时间日期戳&&&&&USHORT&&MajorV&&&&&&&&&&&&&&&//主版本号&&&&&USHORT&&MinorV&&&&&&&&&&&&&&&//小版本号&&&&&ULONG&&&N&&&&&&&&&&&&&&&&&&&&&&&//名字&&&&&ULONG&&&B&&&&&&&&&&&&&&&&&&&&&&&//基址&&&&&ULONG&&&NumberOfF&&&&&&&&&&//函数数&&&&&ULONG&&&NumberOfN&&&&&&&&&&&&&&//名字数&&&&&PULONG&&*AddressOfF&&&&&&&&//函数的地址&&&&&PULONG&&*AddressOfN&&&&&&&&&&&&//名字的地址&&&&&PUSHORT&*AddressOfNameO&&&&&//名字序数的地址&}&IMAGE_EXPORT_DIRECTORY,&*PIMAGE_EXPORT_DIRECTORY;typedef&struct&_IMAGE_IMPORT_DESCRIPTOR&{&&&&union&{&&&&&&&&DWORD&&&C&&&&&&&&&&&&//&0&for&terminating&null&import&descriptor&&&&&&&&DWORD&&&OriginalFirstT&&&&&&&&&//&RVA&to&original&unbound&IAT&(PIMAGE_THUNK_DATA)&&&&};&&&&DWORD&&&TimeDateS&&&&&&&&&&&&&&&&&&//&0&if&not&bound,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//&-1&if&bound,&and&real&date\time&stamp&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//&&in&IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT&(new&BIND)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//&O.W.&date/time&stamp&of&DLL&bound&to&(Old&BIND)&&&&DWORD&&&ForwarderC&&&&&&&&&&&&&&&&&//&-1&if&no&forwarders&&&&DWORD&&&N&&&&DWORD&&&FirstT&&&&&&&&&&&&&&&&&&&&&//&RVA&to&IAT&(if&bound&this&IAT&has&actual&addresses)}&IMAGE_IMPORT_DESCRIPTOR;typedef&IMAGE_IMPORT_DESCRIPTOR&UNALIGNED&*PIMAGE_IMPORT_DESCRIPTOR;我们知道,PE文件在没有装入内存之前,导入表结构中由OriginalFirstThunk和FirstThunk指向的typedef&struct&_IMAGE_THUNK_DATA32&{&&&&union&{&&&&&&&&PBYTE&&ForwarderS&&&&&&&&PDWORD&F&&&&&&&&DWORD&O&&&&&&&&PIMAGE_IMPORT_BY_NAME&&AddressOfD&&&&}&u1;}&IMAGE_THUNK_DATA32;typedef&IMAGE_THUNK_DATA32&*&PIMAGE_THUNK_DATA32;结构数组中的值是相同的,注意,这个结构定义为一个联合,实际上就是一双字,这个结构用来指定一个导入函数,但双字的最高位是1时,表示函数是以序号的方式导入的,这时双字的低位字就是函数的序号,但双字的高位为0时,表示函数以字符类型的函数名方式导入,这时的双字的值就是一个RVA,指向一个结构:typedef&struct&_IMAGE_IMPORT_BY_NAME&{&&&&WORD&&&&H&&&&BYTE&&&&Name[1];}&IMAGE_IMPORT_BY_NAME,&*PIMAGE_IMPORT_BY_NAME;其中Hint表示函数的序号,name【】定义了导入函数的名称;但是为什么要两个一模一样的IMAGE_THUNK_DATA数组呢,让我们先来回顾下调用导入函数的指令:在RebPE中找到oep后,F8跟踪,你能看到这个函数:&&|.&&53&&&&&&&&&&&&push&&&&ebx&&|.&&56&&&&&&&&&&&&push&&&&esi&&|.&&57&&&&&&&&&&&&push&&&&edi&&|.&&8965&E8&&&&&&&mov&&&&&dword&ptr&[ebp-18],&es>&&|.&&FF15&&call&&&&dword&ptr&[405028]&&&&&;&&kernel32.GetVersionCall&&dword&ptr[405028],&&直接寻址方式,将405028处的数据内存属性转换为Dword后作为函数的地址调用;我们可以在提示窗口中:ds:[C81126A&(kernel32.GetVersion)&&&可见,在这个地址中存放的是(kernel32.GetVersion)导入函数的入口地址;这样,call&调用将Eip压入堆栈后,程序执行流就到kernel32中了;还有一种调用方式:就是call&&aaaaaaaa&Aaaaaaaa&&&jmp&dword&ptr&【xxxxxxxx】,这个指令是一个间接寻址的跳转指令,如果你在16进制下查看这个ptr[xxxxxxx]的xxxxxxxx,你会发现它存放的是一个指向欲调用的导入函数名的字符串的RVA地址;当PE文件被装载时,windows装载器根据这个xxxxxxxx处的Rva得到函数名,然后用GetProcAddress函数找到内存中此导入函数的地址,并将xxxxxxxx处的内容替换成真正的函数地址;此时firstthunk指向的DWOWD数组中原本指向函数名的RVA被替换成导入函数的真正入口地址;在PE文件中,所有DLL对应的导入地址数组在位置上是被排列在一起的,全部这写数组的组合也被称为导入地址表,IAT;导入表中第一个IMAGE_IMPORT_DESCRIPTOR结构的FirstThunk字段指向的就是IAT的起始地址;还有就是数据目录表中的13项,可以直接用来定位IAT的地址;&不过一般还是以上一种方法为准;到这里,我们可以来思考手动查找IAT的方法了,由于所有DLL模块的firstThunk数组一般都被放在一块,组成了输入地址表,注意:&这里是一般,不是完全,加密解密三上就有IAT被分开存放的例子,大家可以看下;所以我们只要在找到OEP后,进入到原PE文件的代码块后,找到一个API调用的地址;如:&&|.&&FF15&&call&&&&dword&ptr&[405024]&&&&&;&[GetCommandLineA004011AA&&|.&&A3&F8894000&&&mov&&&&&dword&ptr&[4089F8],&ea>在[405024]右键-》数据窗口中跟随,内存地址;在数据窗口中数据如下:&&AD&2F&81&7C&6A&12&81&7C&FA&CA&81&7C&1A&1E&80&7C&&?亅j&亅?亅&&
阅读(6733) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。

我要回帖

更多关于 dump抓取工具 的文章

 

随机推荐