dll的写法
一共两种
全部写在dllmain函数内
extern "C" _declspec(dllexport)DWORD Sum(int nArg1,char*nArgv2)
{
MessageBox(0,"this Sum call",0,MB_OK);
return nArg1;
}
extern "C"
表示使用C的编译方式编译,C++格式
_declspec(dllexport)
将一个函数申明为导出函数
就申明了一个导出函数
但是这中创建的dll的导出函数序号是连续的,我们不可控的。
也就是Base是1,然后符号表从1 开始。
2
项目新建
添加一个def文件
def中的代码
LIBRARY "def导出函数Demo"
EXPORTS
test1 @1
test2 @5
test3 @8
dllmain中的代码
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
void test3()
{
MessageBox(0,"test3",0,MB_OK);
}
void test2()
{
MessageBox(0,"test2",0,MB_OK);
}
void test1()
{
MessageBox(0,"test1",0,MB_OK);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
def里面定义的就是函数名和序号对应关系
在PE解析工具中,在AddressOfNameOrdinals 中对应的是减去Base的值,可以用这个值直接去AddressOfFunction 表中找到这个偏移,就能拿到这个函数在dll中的地址了
加载dll的几种方式
Demo1
创建空项目
main.c代码
#include "stdio.h"
#include <Windows.hc
int main()
{
typedef void (*func)();
HMODULE hMo = LoadLibrary("dll.dll");
func T3 = (func)(GetProcAddress(hMo,"test3"));
//func T3 = (func)(GetProcAddress(hMo,MAKEINTRESOURCE(8)));
T3();
}
Demo2
main.c代码
#include "stdio.h"
#include <Windows.h>
int main()
{
int(*func)();
HMODULE hMo = LoadLibrary("dll.dll");
(FARPROC*)func = GetProcAddress(hMo,"test3");
//(FARPROC*)func = GetProcAddress(hMo, MAKEINTRESOURCE(8));
func();
}
以序号查找导出函数地址 使用关键字 MAKEINTRESOURCE()
括号中值填序号表中对应值+Base
例如你要导入上面dll 序号为8的函数
这里假如基值为1
- 第一步,找到序号表的VA,遍历序号表
- 第二步,当序号表对应的值+1=8时,这里面的值7就是你要找到的函数符号了
- 第三步,拿这个符号表中的值(7),在地址表中对应偏移就是这个函数地址了(地址表VA+4*7,这个地址你要找以8为序号导出函数的地址)
调试DLL
可能有人疑惑,dll怎么调试,加载的时候又不能printf打印消息
其实是可以使用DbgPrint
来向操作系统发送dbg消息的
然后使用DebugView
来获取系统的调试信息,包括内核调试信息,都是能够获取到的