看了几个源代码 为什么不直接使用API
都是类似这样 间接 调用API
typedef struct _API {
#ifdef WIN32
// Kernel32 Functions. ----------------------
FARPROC(BOAPI*pGetProcAddress) ( HMODULE hModule, LPCSTR lpProcName );
HANDLE(WINAPI *pGetProcessHeap) ( void );
void *(WINAPI *pHeapAlloc)( HANDLE hHeap, DWORD dwFlags, DWORD dwBytes );
HINSTANCE(WINAPI *pLoadLibrary) ( LPCTSTR lpLibFileName );
BOOL(WINAPI *pFreeLibrary)( HMODULE hLibModule);
BOOL(WINAPI *pCloseHandle)( HANDLE hObject );
BOOL(WINAPI *pCopyFile)( LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, BOOL bFailIfExists );
BOOL(WINAPI*pCreateDirectory) ( LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes );
HANDLE(WINAPI *pCreateFile)( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile );
HANDLE(WINAPI *pCreateFileMapping) ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpName);
HANDLE(WINAPI *pCreateMutex)( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName );
BOOL(WINAPI *pCreateProcess) ( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags,LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation );
HANDLE(WINAPI *pCreateRemoteThread) ( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
HANDLE(WINAPI *pCreateThread)( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
BOOL(WINAPI *pDuplicateHandle) ( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions );
BOOL(WINAPI *pDeleteFile)( LPCTSTR lpFileName );
void(WINAPI *pExitProcess)( UINT uExitCode );
VOID(WINAPI *pExitThread)( DWORD dwExitCode );
void(WINAPI *pEnterCriticalSection) ( LPCRITICAL_SECTION lpCriticalSection );
BOOL(WINAPI *pFileTimeToLocalFileTime)( CONST FILETIME *lpFileTime, LPFILETIME lpLocalFileTime );
BOOL(WINAPI *pFileTimeToSystemTime)( CONST FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime );
BOOL(WINAPI*pFindClose)( HANDLE hFindFile );
HANDLE(WINAPI *pFindFirstFile) ( LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData );
BOOL(WINAPI*pFindNextFile)( HANDLE hFindFile, LPWIN32_FIND_DATA lpFindFileData );
BOOL(WINAPI *pFlushFileBuffers) ( HANDLE hFile );
BOOL(WINAPI *pFlushViewOfFile) ( LPCVOID lpBaseAddress, DWORD dwNumberOfBytesToFlush );
LPTSTR(WINAPI *pGetCommandLine) ( VOID );
BOOL(WINAPI *pGetComputerName) ( LPTSTR lpBuffer, LPDWORD nSize );
DWORD(WINAPI *pGetCurrentDirectory) ( DWORD nBufferLength, LPTSTR lpBuffer );
HANDLE(WINAPI *pGetCurrentProcess) ( VOID );
DWORD(WINAPI *pGetCurrentProcessId) ( VOID );
HANDLE(WINAPI *pGetCurrentThread) ( VOID );
DWORD(WINAPI *pGetCurrentThreadId) ( VOID );
BOOL(WINAPI *pGetDiskFreeSpace) ( LPCTSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters );
UINT(WINAPI *pGetDriveType)( LPCTSTR lpRootPathName );
BOOL(WINAPI *pGetExitCodeThread) ( HANDLE hThread, LPDWORD lpExitCode );
DWORD(WINAPI *pGetFileAttributes) ( LPCTSTR lpFileName );
DWORD(WINAPI *pGetFileSize)( HANDLE hFile, LPDWORD lpFileSizeHigh );
VOID(WINAPI *pGetLocalTime)( LPSYSTEMTIME lpSystemTime );
DWORD(WINAPI *pGetLogicalDriveStrings)( DWORD nBufferLength, LPTSTR lpBuffer );
DWORD(WINAPI *pGetModuleFileName) ( HMODULE hModule, LPTSTR lpFilename, DWORD nSize );
HMODULE(WINAPI *pGetModuleHandle) ( LPCTSTR lpModuleName );
UINT(WINAPI *pGetPrivateProfileInt) ( LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault, LPCTSTR lpFileName );
DWORD(WINAPI *pGetPrivateProfileSection)( LPCTSTR lpAppName, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName );
DWORD(WINAPI *pGetPrivateProfileSectionNames) ( LPTSTR lpszReturnBuffer, DWORD nSize, LPCTSTR lpFileName );
DWORD(WINAPI *pGetPrivateProfileString)( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName );
BOOL(WINAPI *pGetPrivateProfileStruct)( LPCTSTR lpszSection, LPCTSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCTSTR szFile );
VOID(WINAPI *pGetSystemInfo) ( LPSYSTEM_INFO lpSystemInfo );
UINT(WINAPI *pGetSystemDirectory) ( LPTSTR lpBuffer, UINT uSize );
VOID(WINAPI *pGetSystemTime) ( LPSYSTEMTIME lpSystemTime );
DWORD(WINAPI *pGetTickCount)( VOID );
DWORD(WINAPI*pGetTempPath)( DWORD nBufferLength, LPTSTR lpBuffer );
为什么不直接使用API?
[解决办法]
使用中间函数指针,可以有好几方面的好处,比如跨平台的代理函数实现,中间代理HOOK,以及自定义函数。同样一个东西,并不是操作系统API的就是最好的,最实用的。
[解决办法]
这是要在内存中搜索API入口。病毒和木马自己一般是不link到kernel32.dll这样的库的,都是运行起来之后,在内存里搜索API入口。
[解决办法]
使用如上的代码是为了实现所谓的“代码完全重定位”的目的,就是代码可以随意放置到合法的内存地址里面执行,克服普通PE文件的固定地址的束缚。主要用途是代码注入,无进程运行代码,多为蠕虫和木马所用。
一个普通的PE加载过程大约是:申请Pe文件建议的内存地址,沿此地址将磁盘中的Pe文件按内存对齐拷贝到内存中,按节属性初始化节,初始化导入函数表,跳入Pe入口执行之。
在一个普通的PE文件中正常调用一个API要用到“导入函数表”这样一个结构,在代码中调用MessageBox(),程序并不直接调用MessageBox函数,而是调用该函数导入表中的FirstShrink,再由FirstShrink跳转到MessageBox()执行。这些都是固定地址方式下的调用,可以说是环环相扣,缺一不可。
假设把一段代码注入到“记事本”进程里面,代码如何知道导入表在哪儿?即使知道了,但导入表中没有注入代码的导入函数又该怎么办?
所以得使用楼主帖出来的API巢(API nest)。API nest可以解决上面提到的难题。
API巢初始化以后,在同一个进程内实现完全重定位的、地址无关的API调用。但代码注入如果到了另一个进程中,就得再次初始化API nest。
这些问题不是三言两语就说完的,有很多知识。
[解决办法]
他说的大概是这个:
.text:00401596 push ebx ; uType
.text:00401597 push offset Caption ; "SetLowerFilters "
.text:0040159C push offset Text ; "Install failed! "
.text:004015A1 push ebx ; hWnd
.text:004015A2 call ds:MessageBoxA ;要调用MessageBoxA,跳过去:
.idata:0041D420 ; int __stdcall MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType)
.idata:0041D420 extrn MessageBoxA:dword ; DATA XREF: sub_401310+292r
.idata:0041D420 ; sub_401310+314r ...
你可以看到PE文件的导入节其实也是和函数指针差不多的,因为编译这个exe的时候,编译器显然是不知道这个MessagBoxA的入口地址在哪里的,因此也就无法生成绝对地址,它只能做个标记,记录调用了哪个模块里的什么函数,装载器在把exe装入内存时会一并将用到的dll装入内存,这时候装载器会用MessageBoxA真实的地址去替换,你可以看到IDA用extrn MessageBoxA:dword 来修饰这个函数指针。这个dword存放的就是MessageBoxA的真实的绝对地址了。