鞋点胶机针头规格重位怎么回事

扫二维码下载作业帮
3亿+用户的选择
下载作业帮安装包
扫二维码下载作业帮
3亿+用户的选择
(2009o鼓楼区二模)下列事例中,为了减小压强的是(  )A.重汽车装有许多很宽的车轮B.压路机上碾子的质量很大C.注射器的针头做得很尖D.滑冰运动员的冰鞋上装有冰刀
免得你要对
扫二维码下载作业帮
3亿+用户的选择
A、重汽车装有许多很宽的车轮,是在压力一定时,增大受力面积来减小压强,符合题意.B、压路机上碾子的质量很大、重力大、对地面的压力大,是在受力面积一定时,增大压力来增大压强,不符合题意.C、注射器的针头做得很尖,是在压力一定时,减小受力面积来增大压强,不符合题意.D、滑冰运动员的冰鞋上装有冰刀,是在压力一定时,减小受力面积来增大压强,不符合题意.故选A.
为您推荐:
扫描下载二维码百度拇指医生
&&&普通咨询
您的网络环境存在异常,
请输入验证码
验证码输入错误,请重新输入在NT环境下隐藏进程,也就是说在用户不知情的条件下,执行自己的代码的方法有很多种,比如说使用注册表插入DLL,使用Windows挂钩等等。其中比较有代表性的是Jeffrey Richer在《Windows核心编程》中介绍的LoadLibrary方法和罗云彬在《windows环境下32位汇编语言程序设计》中介绍的方法。两种方法的共同特点是:都采用远程线程,让自己的代码作为宿主进程的线程在宿主进程的地址空间中执行,从而达到隐藏的目的。相比较而言,Richer的方法由于可以使用c/c++等高级语言完成,理解和实现都比较容易,但他让宿主进程使用LoadLibrary来装入新的DLL,所以难免留下蛛丝马迹,隐藏效果并不十分完美。罗云彬的方法在隐藏效果上绝对一流,不过,由于他使用的是汇编语言,实现起来比较难(起码我写不了汇编程序:))。笔者下面介绍的方法可以说是对上述两种方法的综合:采用c/c++编码,实现完全隐藏。并且,笔者的方法极大的简化了远程线程代码的编写,使其编写难度与普通程序基本一致。基础知识  让自己的代码作为宿主进程的线程,在宿主进程的地址空间中执行确实是个不错的主意。但是要自己把程序放到其他进程的地址空间中去运行,将面临一个严峻的问题:如何实现代码重定位。关于重定位问题,请看下面的程序:
&&int&func()//函数func的定义&&&int&a&=&func();//对func的调用&&这段程序经过编译链接后,可能会变成下面的样子:&&&<span style="COLOR: #x:&push&ebp//这是函数func的入口&<span style="COLOR: #x:&mov&ebp,&esp&&&<span style="COLOR: #x:&call&<span style="COLOR: #401800//对函数func的调用&<span style="COLOR: #x:&mov&dword&ptr&[ebp-<span style="COLOR: #],&eax&&&
  请注意&0x&处的直接寻址指令&call &。上面的程序在正常执行(由windows装入并执行)时,因为PE文件的文件头中含有足够的信息,所以系统能够将代码装入到合适的位置从而保证地址&&处就是函数func的入口。但是当我们自己把程序装入到其他进程的地址空间中时,我们无法保证这一点,最终的结果可能会象下面这样:
&&<span style="COLOR: #x:&push&ebp//这是函数func的入口&<span style="COLOR: #x:&mov&ebp,&esp&&&<span style="COLOR: #x:&call&<span style="COLOR: #401800//<span style="COLOR: #401800处是什么&<span style="COLOR: #x:&mov&dword&ptr&[ebp-<span style="COLOR: #],&eax&&&
  显然,运行上面的代码将产生不可预料的结果(最大的可能就是执行我们费尽千辛万苦才装入的代码的线程连同宿主进程一起被系统杀死)。 不知大家注意过系统中动态链接库(dll)的装入没有:一个dll被装入不同进程时,装入的地址可能不同,所以系统在这种情况下也必须解决dll中直接寻址指令的重定位问题。原来,绝大多数dll中都包含一些由编译器插入的用于重定位的数据,这些数据就构成了重定位表。系统根据重定位表中的数据,修改dll的代码,完成重定位操作。Richer使用的LoadLibrary也是借用了这一点。所以我们的重定位方法就是:替系统来完成工作,自己根据重定位表中的数据进行重定位。既然如此,那就让我们来了解一下重定位表吧。  先来分析一下重定位表中需要保存哪些信息。还以上面的代码为例,要让它能正确执行,就必须把指令&call &改为&call &。进行这一改动需要两个数据,第一是改哪,也就是哪个内存地址中的数据需要修改,这里是&0x&(不是&0x&);第二是怎么改,也就是应该给该位置的数据加上多少,这里是&0x&。这第二个数据可以从dll的实际装入地址和建议装入地址计算而来,只要让前者减后者就行了。其中实际装入地址装入的时候就会知道,而建议装入地址记录在文件头的ImageBase字段中。所以,综上所述,重定位表中需要保存的信息是:有待修正的数据的地址。
页起始地址(RVA)
重定位块长度
第一个重定位项,32位都须修正
第二个重定位项,32位都须修正
第三个重定位项,32位都须修正
第四个重定位项,用于对齐
页起始地址(RVA)
重定位块长度
第一个重定位项,32位都须修正
第二个重定位项,32位都须修正
其他重定位块
重定位表结束标志
  知道了重定位表要保存哪些信息,我们再来看看PE文件的重定位表是如何保存这些信息的。重定位表的位置和大小可以从PE文件头的数据目录中的第六个IMAGE_DATA_DIRECTORY结构中获取。由于记录一个需要修正的代码地址需要一个双字(32位)的存储空间,而且程序中直接寻址指令也比较多,所以为了节省存储空间,windows把重定位表压缩了一下,以页(4k)为单位分块存储。在一个页面中寻址只需要12位的数据,把这12位数据再加上4位其它数据凑齐16位就构成一个重定位项。在每一页的所有重定位项前面附加一个双字表示页的起始地址,另一个双字表示本重定位块的长度,就可以记录一个页面中所有需要重定位的地址了。所有重定位块依次排列,最后以一个页起始地址为0的重定位块结束重定位表。上表是一个重定位表的例子(表中每种颜色代表一个重定位块)。   上面提到每个重定位项还包括4位其他信息,这4位是重定位项的高4位,虽然有4位,但我们实际上能看到的值只有两个:0和3。0表示此项仅用作对齐,无其他意义;3表示重定位地址指向的双字的32位都需要修正。还要注意一点的是页起始地址是一个相对虚拟地址(RVA),必须加上装入地址才能得到实际页地址。例如上表中的第一个重定位项表示需要重定位的数据位于地址(假设装入地址是h):装入地址(h)+页地址(1000h)+页内地址(0006h)=h。
重定位数据在内存内的情况如下图所示:
  至此,已经解决了重定位问题。应该说,现在我们已经能够开始编码了。但是,不知你是否读过其它有关进程隐藏的文章(使用类似Jeffrey Richer的方法的例外)并且注意到它们总是以显式链接的方式调用Windows API,例如下面对MessageBox的调用:
//fnLoadLibrary和fnGetProcAddress分别指向Windows&API函数LoadLibraryW和GetProcAddress&typedef&int&(WINAPI&*FxMsgBox)(HWND,&LPCWSTR,&LPCTSTR,&UINT);&&&HMODULE&hUser32&=&fnLoadLibrary(L&User32.dll&);&FxMsgBox&fnMsgBox&=&(FxMsgBox)(fnGetProcAddress(hUser32,&&MessageBoxW&));&fnMsgBox(&);&&
  那它们为什么不使用更简便的隐式链接呢?原来,要隐式链接dll并调用其中的输出函数,首先必须保证程序运行时dll已经被装入,否则就会出错。其次,调用API函数的指令格式一般是:call dword ptr [xxxxxxxx],要让程序正常运行,就必须在调用前在地址&xxxxxxxx&处填入目标函数的入口地址。程序正常装入时,系统会保证这两点。但是要自己装入程序,保证这两点就有一些麻烦,所以它们一般使用显式链接来绕过这两个问题。   如果你不在乎为每一个API使用一个typedef和一个GetProcAddress的话(也许还有一个LoadLibrary),使用显式链接就已经足够好了。但是设想一下实际情况吧:你的代码中调用几十乃至数百个API的情况是很常见的,为每一个API写这些重复性的代码将使编程毫无乐趣可言,所以,我们一定要解决那两个问题,从而使用隐式链接。
即:我们将自己的程序装载到宿主的exe里时应该用隐式连接。
我们处理隐式链接问题的思路和前面处理重定位问题时是一样的,即:替系统来完成工作,在远程线程代码调用第一个API之前,装入dll并填好相关入口地址。
//摘自WINNT.H
typedef&struct&_IMAGE_IMPORT_DESCRIPTOR&{&&&&&union&{&DWORD&C&DWORD&OriginalFirstT&&&&&};&&&&&DWORD&TimeDateS&&&&&DWORD&ForwarderC&&&&&DWORD&N&&&&&DWORD&FirstT&}&IMAGE_IMPORT_DESCRIPTOR;
  还是先来学习一下基础知识&PE文件的输入表。输入表记录了一个Win32程序隐式加载的所有dll的文件名及从中引入的API的函数名,通过PE文件头的数据目录中的第二个IMAGE_DATA_DIRECTORY,我们可以获得输入表的位置和大小。实际上,输入表是一个由IMAGE_IMPORT_DESCRIPTOR结构组成的数组,每个结构对应一个需要隐式加载的dll文件,整个输入表以一个Characteristics字段为0的IMAGE_IMPORT_DESCRIPTOR结束。上面就是IMAGE_IMPORT_DESCRIPTOR结构的定义。   其中的Name字段是一个RVA,指向此结构所对应的dll的文件名,文件名是以NULL结束的字符串。在PE文件中,OriginalFirstThunk和FirstThunk都是RVA,分别指向两个内容完全相同的IMAGE_THUNK_DATA结构的数组,每个结构对应一个引入的函数,整个数组以一个内容为0的IMAGE_THUNK_DATA结构作为结束标志。IMAGE_THUNK_DATA结构定义如下:
//摘自WINNT.H&typedef&struct&_IMAGE_THUNK_DATA32&{&&&&&union&{&DWORD&ForwarderS&//&PBYTE&DWORD&F&//&PDWORD&DWORD&O&DWORD&AddressOfD&//&PIMAGE_IMPORT_BY_NAME&&&&&}&u1;&}&IMAGE_THUNK_DATA32;&typedef&IMAGE_THUNK_DATA32&IMAGE_THUNK_DATA;
  从上面的定义可以看出,完全能够把IMAGE_THUNK_DATA结构当作一个DWORD使用。当这个DWORD的最高为是1时,表示函数是以序号的形式引入的;否则函数是以函数名的形式引入的,且此DWORD是一个RVA,指向一个IMAGE_IMPORT_BY_NAME结构。我们可以使用在WINNT.H中预定义的常量IMAGE_ORDINAL_FLAG来测试最高位是否为1。IMAGE_IMPORT_BY_NAME结构定义如下:
//摘自WINNT.H&typedef&struct&_IMAGE_IMPORT_BY_NAME&{&&&&&WORD&H&&&&&BYTE&Name[<span style="COLOR: #];&}&IMAGE_IMPORT_BY_NAME;
  其中Hint字段的内容是可选的,如果它不是0,则它也表示函数的序号,我们编程是不必考虑它。虽然上面的定义中Name数组只包含一个元素,但其实它是一个变长数组,保存的是一个以NULL结尾的字符串,也就是函数名。   也许上面的解释已经把你弄得头晕脑涨了,来看看下面的导入表的实际结构吧,希望下图能帮你清醒一下:   光看前面的讲解中,你也许会有一个疑问:既然OriginalFirstThunk和FirstThunk指向的内容完全一样,只用一个不就行了吗?好了,不要再怀疑Windows的设计者了,在PE文件中它们确实是一样的,但是当文件被装入内存后,差别就出现了:OriginalFirstThunk的内容不会变,但FirstThunk里数据却会变成与其相对应的函数的入口地址。内存中的输入表结构如下图所示:  事实上,前面提到的call dword ptr [xxxxxxxx]指令中的&xxxxxxxx&就是FirstThunk中的一个IMAGE_THUNK_DATA的地址,而这个IMAGE_THUNK_DATA在装入完成之后保存的就是与其对应的函数的入口地址。知道动态链接是怎么回事了吧! 编程实现  到现在为止,有关进程隐藏的基础知识就都说完了,下面我们就开始动手编程,其他问题我将结合代码进行说明。   我们要编写两个程序,一个是dll,它里面包含要插入到宿主进程中去的代码和数据;另一个是装载器程序,它将把dll装入宿主进程并通过创建远程线程来运行这些代码。为了更好的隐藏,我把编译好的dll作为资源加入到了装载器之中。至于宿主进程,我选择的是&explorer.exe&,因为每一个windows系统中都有它的身影。装载器程序运行之后,远程线程将弹出如下一个消息框,证明代码插入成功。  两个程序有一个公用的头文件&ThreadParam.h&,我在它里面定义了要传递给远程线程的参数的结构,这个结构包括两个函数指针,使用时,它们将分别指向windows API&LoadLibrary&和&GetProcAddress&,还有一个指针指向远程线程在目标进程中的映像基址,后面将对这三个指针进行具体说明,下面是&ThreadParam.h&的内容:
typedef&HMODULE&(WINAPI&*FxLoadLibrary)(LPCSTR&lpFileName);&typedef&FARPROC&(WINAPI&*FxGetProcAddr)(HMODULE&hModule,&LPCSTR&lpProcName);&typedef&struct&tagTHREADPARAM&{&&&&&FxLoadLibrary&fnLoadL&&&&&FxGetProcAddr&fnGetProcA&&&&&LPBYTE&pImageB&}THREADPARAM,&*PTHREADPARAM;
  我们先来看装载器程序。这里面还会涉及到其他一些PE文件格式方面的内容,限于篇幅,我将不再详细介绍,请读者参考相关资料。同时,为了使程序更加短小,我假设它从不出错,去掉了所有用于错误处理的代码。 首先介绍一下程序中用到的全局变量和常数。其中&_pinh&指向嵌入装载器的dll的PE文件头,供需要的地方使用。之后的四个宏是为了以后程序书写方便而定义,&IMAGE_SIZE&表示dll的映像大小,也就是需要在宿主进程中开辟多大的内存空间;&RVA_EXPORT_TABEL&表示dll输出表的RVA地址;&RVA_RELOC_TABEL&表示dll重定位表的RVA地址;&PROCESS_OPEN_MODE&表示打开宿主进程的方式,只有按这种方式打开,我们才能完成所有必需的工作。
static&PIMAGE_NT_HEADERS&_pinh&=&NULL;&#define&IMAGE_SIZE&(_pinh-&OptionalHeader.SizeOfImage)&#define&RVA_EXPORT_TABEL&(_pinh-&OptionalHeader.DataDirectory[0].VirtualAddress)&#define&RVA_RELOC_TABEL&(_pinh-&OptionalHeader.DataDirectory[5].VirtualAddress)&#define&PROCESS_OPEN_MODE&(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION)下面是主函数的定义,从中我们可以看到大致的工作步骤,注释中的序号标明了每一步的开始位置。int&APIENTRY&_tWinMain(HINSTANCE&hInst,&HINSTANCE,&LPTSTR&lpCmdLine,&int&nCmdShow)&{&&&&&LPTHREAD_START_ROUTINE&pEntry&=&NULL;&&&&&PTHREADPARAM&pParam&=&NULL;&&&&&LPBYTE&pImage&=&(LPBYTE)MapRsrcToImage();&//①&&&&&DWORD&dwProcessId&=&GetTargetProcessId();&//②&&&&&HANDLE&hProcess&=&OpenProcess(PROCESS_OPEN_MODE,&FALSE,&dwProcessId);&&&&&LPBYTE&pInjectPos&=&(LPBYTE)VirtualAllocEx(hProcess,&NULL,&IMAGE_SIZE,&&&&&MEM_COMMIT,&PAGE_EXECUTE_READWRITE);&&&&&PrepareData(pImage,&pInjectPos,&(PVOID*)&pEntry,&(PVOID*)&pParam);&//③&&&&&WriteProcessMemory(hProcess,&pInjectPos,&pImage,&IMAGE_SIZE,&NULL);&//④&&&&&HANDLE&hThread&=&CreateRemoteThread(hProcess,&NULL,&<span style="COLOR: #,&pEntry,&pParam,&<span style="COLOR: #,&NULL);&&&&&CloseHandle(hThread);&//⑤&&&&&CloseHandle(hProcess);&&&&&VirtualFree(pImage,&<span style="COLOR: #,&MEM_RELEASE);&&&&&return&<span style="COLOR: #;&}
第①步:将资源中的dll文件映射到内存,形成映像。这一步由函数&MapRsrcToImage&完成。它首先将打开资源中的dll,找到dll的PE文件头并让全局变量_pinh指向它。然后,它再根据文件头中的&SizeOfImage&字段在装载器进程(为求方便,我们的数据准备工作都在装载器进程中实现,只是到最后,才把准备好的数据一次性写入宿主进程)中开辟足够的内存空间用于存放dll的内存映像。把dll映射到内存的操作是以节为单位来进行的,PE文件中的节表(IMAGE_SECTION_HEADER)提供了每个节的大小、在文件中的位置和要放到内存中的位置(RVA)等信息。文件头不属于任何节,我们把它的数据放到内存区的起始位置(这样做是有原因的,将在介绍dll程序时说明)。
static&LPBYTE&MapRsrcToImage()&//将资源中的DLL映射到内存&{&&&&&HRSRC&hRsrc&=&FindResource(NULL,&_T(&rtdll&),&_T(&RT_DLL&));&&&&&HGLOBAL&hGlobal&=&LoadResource(NULL,&hRsrc);&&&&&LPBYTE&pRsrc&=&(LPBYTE)LockResource(hGlobal);&&&&&_pinh&=&(PIMAGE_NT_HEADERS)(pRsrc&+&((PIMAGE_DOS_HEADER)pRsrc)-&e_lfanew);&&&&&LPBYTE&pImage&=&(LPBYTE)VirtualAlloc(NULL,&IMAGE_SIZE,&MEM_COMMIT,&PAGE_READWRITE);&&&&&DWORD&dwSections&=&_pinh-&FileHeader.NumberOfS&&&&&DWORD&dwBytes2Copy&=&(((LPBYTE)_pinh)&-&pRsrc)&+&sizeof(IMAGE_NT_HEADERS);&&&&&PIMAGE_SECTION_HEADER&pish&=&(PIMAGE_SECTION_HEADER)(pRsrc&+&dwBytes2Copy);&&&&&dwBytes2Copy&+=&dwSections&*&sizeof(IMAGE_SECTION_HEADER);&&&&&memcpy(pImage,&pRsrc,&dwBytes2Copy);&&&&&for(DWORD&i=<span style="COLOR: #;&i&dwS&i++,&pish++)&&&&&{&&&&&&&&&LPBYTE&pSrc&=&pRsrc&+&pish-&PointerToRawD&&&&&LPBYTE&pDest&=&pImage&+&pish-&VirtualA&&&&&dwBytes2Copy&=&pish-&SizeOfRawD&&&&&memcpy(pDest,&pSrc,&dwBytes2Copy);&&&&&}&&&&&_pinh&=&(PIMAGE_NT_HEADERS)(pImage&+&((PIMAGE_DOS_HEADER)pImage)-&e_lfanew);&&&&&return&pI&}
第②步:打开宿主进程,并在其中开辟用于写入数据的内存空间。这一步比较简单,其中函数&GetTargetProcessId&用于获取&explorer.exe&的进程ID。
static&DWORD&GetTargetProcessId()&//取得explorer进程的pid&{&&   DWORD&dwProcessId&=&<span style="COLOR: #;&&&&&HWND&hWnd&=&FindWindow(_T(&Progman&),&_T(&Program&Manager&));&&&&&GetWindowThreadProcessId(hWnd,&&dwProcessId);&&&&&return&dwProcessId;&}&
第③步:准备好要写入宿主进程的数据。这一步要把①中建立的dll映像根据②中开辟的存储空间的基址进行重定位,为线程准备参数,并计算线程的入口地址。
static&void&PrepareData(LPBYTE&pImage,&LPBYTE&pInjectPos,&PVOID*&ppEntry,&PVOID*&ppParam)&{&&&&&LPBYTE&pRelocTbl&=&pImage&+&RVA_RELOC_TABEL;&&&&&DWORD&dwRelocOffset&=&(DWORD)pInjectPos&-&_inh.OptionalHeader.ImageB&&&&&RelocImage(pImage,&pRelocTbl,&dwRelocOffset);&&&&&PTHREADPARAM&param&=&(PTHREADPARAM)pRelocT&&&&&HMODULE&hKernel32&=&GetModuleHandle(_T(&kernel32.dll&));&  param-&fnGetProcAddress=(FxGetProcAddress)GetProcAddress(hKernel32,&GetProcAddress&);&&&&&param-&fnLoadLibrary=&(FxLoadLibrary)GetProcAddress(hKernel32,&&LoadLibraryA&);&  param-&pImageBase&=&pInjectP&&&&&*ppParam&=&pInjectPos&+&RVA_RELOC_TABEL;&&&&&*ppEntry&=&pInjectPos&+&GetEntryPoint(pImage);&}&
  首先,它根据实际装入地址和建议地址计算出要加到重定位数据上去的数值,然后调用函数&RelocImage&进行重定位操作。&RelocImage&主要是根据我们前面介绍的重定位表的结构来对dll映像进行重定位。看了&RelocImage&的代码,你是不是感到有些惊讶?我们费了那么多气力来说明重定位问题,但实现它却只需要这么几行程序!其实这说明了一点:PE文件格式设计得非常简洁,我们完全没必要对它有恐惧感。后面处理隐式链接的代码将再次证明这一点。
static&void&RelocImage(PBYTE&pImage,&PBYTE&pRelocTbl,&DWORD&dwRelocOffset)&{&&&&&PIMAGE_BASE_RELOCATION&pibr&=&(PIMAGE_BASE_RELOCATION)pRelocT&&&&&while(pibr-&VirtualAddress&!=&NULL)&&&&&{&&&&&WORD*&arrOffset&=&(WORD*)(pRelocTbl&+&sizeof(IMAGE_BASE_RELOCATION));&&&&&DWORD&dwRvaCount&=&(pibr-&SizeOfBlock&-&sizeof(IMAGE_BASE_RELOCATION))&/&<span style="COLOR: #;&&&&&for(DWORD&i=<span style="COLOR: #;&i&dwRvaC&i++&)&&&&&{&&&&&&&&&&&&DWORD&dwRva&=&arrOffset[i];&&&&&&&&&if((dwRva&&&<span style="COLOR: #xf000)&!=&<span style="COLOR: #x3000)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&continue;&&&&&&&&&dwRva&&=&<span style="COLOR: #x0fff;&&&&&&&&&dwRva&+=&pibr-&VirtualAddress&+&(DWORD)pI&&&&&&&&&&&&&*(DWORD*)dwRva&+=&dwRelocO&}&pRelocTbl&+=&pibr-&SizeOfB&pibr&=&(PIMAGE_BASE_RELOCATION)pRelocT&&&&&}&}
  由于我们在宿主进程中分配的内存只有IMAGE_SIZE那么大,所以必须在重定位操作完成之后,才能把线程参数写进去,这是因为重定位表在完成重定位之后,就没用了,我们正好可以借用它的空间来存放线程参数,而且一般情况下,空间足够使用,除非你要传递特别多的参数。这样,参数的地址自然就是实际装入地址加上重定位表的RVA地址了。   最后的工作是获取线程的入口地址,由函数&GetEntryPoint&来完成。我们的dll程序输出一个名为&ThreadEntry&的函数,其原型兼容windows的线程入口函数,我们把它作为远程线程的执行体。GetEntryPoint根据dll的输出表信息从映像中找到ThreadEntry的入口地址并将其返回。不过,&GetEntryPoint&返回的地址是一个RVA,必须加上装入地址&pInjectPos&才是实际入口地址。
static&DWORD&GetEntryPoint(LPBYTE&pImage)&{&&&&&DWORD&dwEntry&=&<span style="COLOR: #,&index&=&<span style="COLOR: #;&&&&&IMAGE_EXPORT_DIRECTORY*&pied&=&(IMAGE_EXPORT_DIRECTORY*)(pImage&+&RVA_EXPORT_TABEL);&&&&&DWORD*&pNameTbl&=&(DWORD*)(pImage&+&pied-&AddressOfNames);&&&&&for(index=<span style="COLOR: #;&index&pied-&NumberOfN&index++,&pNameTbl++)&if(strcmp(&ThreadEntry&,&(char*)(pImage&+&(*pNameTbl)))&==&<span style="COLOR: #)&{&index&=&((WORD*)(pImage&+&pied-&AddressOfNameOrdinals))[index];&dwEntry&=&((DWORD*)(pImage&+&pied-&AddressOfFunctions))[index];&break;&&}&&&&&return&dwE&}
第④步:把准备好的数据写入宿主进程,并创建远程线程来运行写入的代码。 第⑤步:进行装载器程序结束前的清理工作。 以上是装载器程序的全部内容,接下来介绍dll程序。前面已经说过,dll要输出一个名为&ThreadEntry&的函数作为远程线程的入口,所以我们从&ThreadEntry&开始。
extern&DWORD&ThreadMain(HINSTANCE&hInst);&DWORD&WINAPI&ThreadEntry(PTHREADPARAM&pParam)&{&&&&&DWORD&dwResult&=&-<span style="COLOR: #;&&&&&__try{&&&&&&&&&if(LoadImportFx(pParam-&pImageBase,&pParam-&fnLoadLibrary,&pParam-&fnGetProcAddr))&&&&&dwResult&=&ThreadMain((HINSTANCE)pParam-&pImageBase);&&&&&}&&&&&__except(EXCEPTION_EXECUTE_HANDLER)&&&&&{&&&&&dwResult&=&-<span style="COLOR: #;&&&&&}&&&&&return&dwR&}
  整个ThreadEntry的代码被包含在一个SEH(结构化异常处理)之中,这可以避免部分由于寄生代码出错而导致宿主被系统杀死的情况。ThreadEntry首先调用LoadImportFx函数完成隐式链接dll的处理。   LoadImportFx的工作原理就是按照前面介绍的输入表的结构,使用LoadLibrary加载dll文件,然后用GetProcAddress获得输入函数的入口地址并写入相应的IMAGE_THUNK_DATA中。我在这里要说明的是:为什么远程线程能使用装载器进程中LoadLibrary和GetProcAddress的入口地址来实现对这两个函数的调用?因为按照前面的说法,我们无法保证包含这两个函数的dll已被装入,更无法保证它们的指向的正确性。其实,这里我利用了windows系统中的两个事实:一是基本上所有的windows进程都会装入&kernel32.dll&(在我的机器上,只有smss.exe例外),而这两个函数就位于&kernel32.dll&中;另一个是所有装入&kernel32.dll&的进程都会把它装入同一个内存地址,这是因为它是windows系统中最基本的dll之一。所以,我这样使用在绝大多数情况下不会有任何问题。
BOOL&LoadImportFx(LPBYTE&pBase,&FxLoadLibrary&fnLoadLibrary,&FxGetProcAddr&fnGetProcAddr)&{&&&&&PIMAGE_DOS_HEADER&pidh&=&(PIMAGE_DOS_HEADER)pB&&&&&PIMAGE_NT_HEADERS&pinh&=&(PIMAGE_NT_HEADERS)(pBase&+&pidh-&e_lfanew);&&&&&PIMAGE_IMPORT_DESCRIPTOR&piid&=&(PIMAGE_IMPORT_DESCRIPTOR)&  (pBase&+&pinh-&OptionalHeader.DataDirectory[<span style="COLOR: #].VirtualAddress);&&&&&for(;&piid-&OriginalFirstThunk&!=&<span style="COLOR: #;&piid++)&&&&&{&&&&&HMODULE&hDll&=&fnLoadLibrary((LPCSTR)(pBase&+&piid-&Name));&&&&&PIMAGE_THUNK_DATA&pOrigin&=&(PIMAGE_THUNK_DATA)(pBase&+&piid-&OriginalFirstThunk);&&&&&PIMAGE_THUNK_DATA&pFirst&=&(PIMAGE_THUNK_DATA)(pBase&+&piid-&FirstThunk);&&&&&LPCSTR&pFxName&=&NULL;&&&&&PIMAGE_IMPORT_BY_NAME&piibn&=&NULL;&&&&&for(;&pOrigin-&u1.Ordinal&!=&<span style="COLOR: #;&pOrigin++,&pFirst++)&&&&&{&&&&&&&&&&&&&if(pOrigin-&u1.Ordinal&&&IMAGE_ORDINAL_FLAG)&&&&&&&&&&&&&&&&&pFxName&=&(LPCSTR)IMAGE_ORDINAL(pOrigin-&u1.Ordinal);&&&&&  else&       {&&&&&&&&&&&&&&&&&piibn&=&(PIMAGE_IMPORT_BY_NAME)(pBase&+&pOrigin-&u1.AddressOfData);&&&&&&&&&&&&&&&&&pFxName&=&(LPCSTR)piibn-&N&       }&&&&&&&&&&&&&pFirst-&u1.Function&=&(DWORD)fnGetProcAddr(hDll,&pFxName);&&&&&}&&  }&&&&&return&TRUE;&}&
&  处理完隐式链接之后,ThreadEntry调用ThreadMain来进行完成远程线程的实际工作。可能你已经注意到ThreadMain有一个参数是HINSTANCE类型,但从ThreadEntry可知,它实际上是dll在宿主中的装入地址,为什么可以这样做呢?答案是:我不知道,你去问微软吧。不过据我观察,普通程序的任何一个模块(module)的句柄都是其装入地址,所以我也就照猫画虎了。这也解释了前面处理重定位时把文件头放入映像基址的原因&系统需要文件头信息,我必须为它准备好(虽然LoadImportFx函数也需要文件头来定位输入表,但不是根本原因,因为完全可以让它使用其他方式)。   下面是我的ThreadMain,它弹出前面提到的消息框。看到了吧?你可以像写普通程序一样写远程线程的代码,没有复杂的自定位,也没有烦人的显式链接,这个世界真美好! 小结  本文在相当大的程度上简化了进程隐藏技术,你甚至可以把它当作一个模板,仅仅实现一个ThreadMain就可以把代码隐藏到其他进程中去为所欲为了。但这决不是笔者写作此文的目的,我希望读者只把它当作一项技术,加深自己对windows系统的理解。其实,本文对动态链接的处理还远没有达到操作系统程度,举例来说:PE文件的数据目录现在使用了15项,但本文只处理了4项:输出表,输入表,重定位表和IAT(可以看作输入表的一部分),不把所有15项都处理完,远程代码的行为就可能与正常情况不同。我希望能与各位读者共同努力,不断完善这项技术,更希望大家能够负责任的使用它,利用它更好的防治各种有害代码。
本文已收录于以下专栏:
相关文章推荐
1.逻辑地址空间
  在多道程序设计中,往往会有多个作业同时存放在内存中,而每个用户预先无法知道他的作业被装在主存的什么位置,为了方便编程,每个用户可以认为自己的程序和数据放在从O地址开始的...
链接和重定位是嵌入式C中很重要的部分,对于这一块掌握的越精细越好。
指令位置分类
指令分为两种:
位置无关编码(PIC):汇编源文件被编码成二进制可执行程序时编码方式与位置(内存地址)...
dll的建议装载地址在编译的时候就已经确定了,多个dll加载时建议装入地址会冲突,windows的装载器会根据pe文件的重定位表将需要修正的地址进行修正。
修正时需要三个值
1.实际的装载地址(w...
标 题:DLL文件脱壳(重定位表修复部分)作 者:kanxue 时 间: 10:42
链 接:/showthread.php?t=6133...
DLL 重定位在32位代码中,涉及到直接寻址的指令都是需要重定位的(而在DOS的16位代码中,只有涉及到段操作的指令才是需要重定位的,对此有兴趣的读者可以参考 相关的资料),对于操作系统来说,其任务就...
最近读程序员的自我修养--链接 装载与库,其中有句话:动态链接模块被装载映射到虚拟空间后,指令部分是在多个进程之间共享的,由于装载时重定位的方法需要修改指令,所以没有办法做到同一份指令被多个进程共享,...
共享库载入时重定位
原作者:Eli Bendersky
http://eli.thegreenplace.net//load-time-relocation-of-shared...
为了决定段的大小、符号定义、符号引用,并指出包含那些库模块、将这些段放置在输出地址空间的什么地方,链接器会将所有的输入文件进行扫描。扫描完成后的下一步就是链接过程的核心,重定位。由于重定位过程的两个步...
作者:RayeWang
www.raye.wang//quan-mian-liao-jie-nginxdao-di-neng-zuo-shi-yao/
今天中午去面了一家互联网公司,在谈及到数据库这块时,被闻到了一个很好的问题,就是数据库集群的实现方式,之前在网上看到关于mysql数据库集群的现成的框架,比如Galera,它是支持多个服务器的库同时同...
他的最新文章
讲师:董岩
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)}

我要回帖

更多关于 点胶机针头 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信