FASM在构建输入表的时候只需要符号即可,并不像VC那样需要lib,这是FASM编译速度快的因素之一。
而FASM从官网上下载的时候,windows的函数库是不全的,连最常用的都没有,只好手动添加了。
在include\api文件夹下,稍微看一下就能搞懂格式。
一般情况下,FASM编译时是不会检查函数的参数个数的,除非在include\pcount下有相应的声明。
我就写了个给FASM导入函数的小工具,便于开发,手动一个一个写太费劲了。
函数少一些还凑合,可是系统的DLL一弄都是上百个,用的时候加一点,时间久了就烦了。
写这个工具,一劳永逸。。。。。。
-----------
思路就是用户输入DLL文件名或者路径,把这个DLL加载到内存,分析导出表,然后按照FASM的格式来整理出一份文件。
代码如下:
Header.h
#ifndef _INCLUDE_HEADER_H_
#define _INCLUDE_HEADER_H_
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "msvcrt.lib")
typedef struct _FUNC_LINK
{
PCHAR pFuncName;
_FUNC_LINK *pNext;
}FUNC_LINK, *PFUNC_LINK;
#endif
Entry.cpp
#include "Header.h"
PFUNC_LINK g_pLink = NULL;
int main(int argc, PCHAR argv[])
{
HANDLE hDll, hFile;
DWORD dwTmp, *pFuncName;
CHAR *pNames, szDstFile[MAX_PATH], *pDllName, szWrite[70], szTmp[30];
PFUNC_LINK pCurrNode = NULL, pTmpNode;
PIMAGE_EXPORT_DIRECTORY pExport;
system("color 0a");
printf("ExportApi tool for FASM \n"
"This Application able to export functions from dll files\n"
"http://blog.csdn.net/Sidyhe\n\n");
__try
{
if (argc <= 1)
{
printf("Usage:\nExportApi.exe file.dll [or file full path]\n");
__leave;
}
hDll = GetModuleHandle(argv[1]);
if (hDll == NULL)
{
hDll = LoadLibraryEx(argv[1], NULL, DONT_RESOLVE_DLL_REFERENCES);
}
if (hDll == NULL)
{
printf("ERROR_INVALID_PARAMETER\n");
__leave;
}
//转换一步到位,因为镜像已经加载成功了,不存在什么无效PE等问题
pExport = (PIMAGE_EXPORT_DIRECTORY)(((PIMAGE_NT_HEADERS)
(((PIMAGE_DOS_HEADER)hDll)->e_lfanew + (ULONG)hDll))-> \
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
if (pExport == NULL)
{
printf("Find no export table.\n");
__leave;
}
//RVA to VA
pExport = (PIMAGE_EXPORT_DIRECTORY)((ULONG)hDll + (ULONG)pExport);
pFuncName = (PDWORD)(pExport->AddressOfNames + (ULONG)hDll);
//组成链表,不考虑释放了
for (dwTmp = 0; dwTmp < pExport->NumberOfNames; dwTmp++)
{
pNames = (PCHAR)(pFuncName[dwTmp] + (ULONG)hDll);
if (pCurrNode == NULL)//第一个
{
pCurrNode = (PFUNC_LINK)malloc(sizeof(FUNC_LINK));
pCurrNode->pFuncName = pNames;
pCurrNode->pNext = NULL;
g_pLink = pCurrNode;
}
else
{
pCurrNode->pNext = (PFUNC_LINK)malloc(sizeof(FUNC_LINK));
pCurrNode = pCurrNode->pNext;
pCurrNode->pFuncName = pNames;
pCurrNode->pNext = NULL;
}
}
printf("Find %d Functions.\n\n", pExport->NumberOfNames);
GetModuleFileName(NULL, szDstFile, sizeof(szDstFile));
pNames = strrchr(argv[1], '\\');
if (pNames)//是完整路径
{
lstrcpy(strrchr(szDstFile, '\\'), pNames);
pDllName = pNames + 1;
}
else//只是文件名
{
lstrcpy(strrchr(szDstFile, '\\') + 1, argv[1]);
pDllName = argv[1];
}
lstrcpy(strrchr(szDstFile, '.') + 1, "inc");
*strrchr(pDllName, '.') = '\0';
hFile = CreateFile(szDstFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile Error. Code:0x%08X", GetLastError());
__leave;
}
//写import部分
sprintf(szWrite, "import %s", pDllName);
WriteFile(hFile, szWrite, lstrlen(szWrite), &dwTmp, NULL);
for (pCurrNode = g_pLink; pCurrNode; pCurrNode = pCurrNode->pNext)
{
sprintf(szWrite, ", \\\r\n %s, \'%s\'", pCurrNode->pFuncName, pCurrNode->pFuncName);
WriteFile(hFile, szWrite, lstrlen(szWrite), &dwTmp, NULL);
}
//写api部分,与ANSI和UNICODE相关的
sprintf(szWrite, "\r\n\r\napi ");
WriteFile(hFile, szWrite, lstrlen(szWrite), &dwTmp, NULL);
for (pCurrNode = g_pLink; pCurrNode; pCurrNode = pCurrNode->pNext)
{
dwTmp = lstrlen(pCurrNode->pFuncName);
if (pCurrNode->pFuncName[dwTmp - 1] == 'A')
{
//可能是ANSI函数,找UNICODE函数
for (pTmpNode = g_pLink; pTmpNode; pTmpNode = pTmpNode->pNext)
{
if (pTmpNode == pCurrNode) continue;
//SDK没有lstrcmpn???
if(strncmp(pTmpNode->pFuncName, pCurrNode->pFuncName, dwTmp - 1) != 0) continue;
if (pTmpNode->pFuncName[dwTmp - 1] != 'W') continue;
lstrcpyn(szTmp, pCurrNode->pFuncName, dwTmp);
sprintf(szWrite, "%s, \\\r\n ", szTmp);
WriteFile(hFile, szWrite, lstrlen(szWrite), &dwTmp, NULL);
break;
}
}
}
//多写了一次", \"和空格
SetFilePointer(hFile, -12, NULL, FILE_CURRENT);
SetEndOfFile(hFile);
//其实我真不想关,结束了什么都么了
CloseHandle(hFile);
printf("output:\n%s\n", szDstFile);
}
__finally
{
//没必要了,程序立马退出
// FreeLibrary(hDll);
}
ExitProcess(0);
return 0;
}
------------
此工具不适用于自己写的dll,因为不管有没有ANSI和UNICODE(A和W结尾的函数),我都会添加api这个信息。
非要使用的话就把输出后的文件自己整理一下。