dll自定义入口的问题
看到某CSDN文章如下:================================================================================================
关于重新指定Dll入口的问题
大家都明白,在进行Dll开发过程当中,VS将默认指定DllMain为Dll的入口。一般情况下我们需要定义自己的入口,如何让我们的程序在加载Dll时直接
执行的是我们自定义的入口函数呢?我想很多初学者都不是很了解,本人也曾经为此迷惑了许久,为了方便大家的学习,在这里将其贴出来,供大家参考。
其实方法很简单,只需要我们在Project --〉Setting下面的Link标签中的Project Options里面加入/Entry:"MyEntry"即可,其中MyEntry就是我们要指
定的入口方法名称。为此,我们再次编译工程,Dll将以MyEntry为程序入口执行。
================================================================================================
文章就这么多文字,还是不明白指定DLL入口,或是说自定义DLL函数入口,有啥好处。
1
文章中说:如何让我们的程序在加载Dll时直接执行的是我们自定义的入口函数呢?这是啥意思?请写个demo例子说明一下
2
另外,不使用dllmain做入口而使用自定义入口还没有其他别的用处?也请写demo说明一下。 以vs举例,其他的可能也大差不差。
你写一个动态库,一般来说入口点就是DllMain,编译器会自动链接SDK中的crtdll.c文件(或类似的),里面是真正的入口点_DllMainCRTStartup,如果是DLL_PROCESS_ATTACH的话就__security_init_cookie,接着调用__DllMainCRTStartup(与前面的_DllMainCRTStartup有区别,这个函数是两个下划线开头),在__DllMainCRTStartup中会做一些_CRT_INIT之类的初始化工作,然后才会去调用DllMain。
如果你没有实现DllMain,那么链接就会错误。这个就是默认情况下,非自定义入口点的编译和执行情况。
自定义入口点的意思就是,你编译器不要给我链接crtdll.c了,我自己指定一个函数作为入口点。
比如还是DllMain作为自定义入口点,_DllMainCRTStartup和__DllMainCRTStartup以及_CRT_INIT之类的都不会被调用到,你需要自己去做这些初始化工作。
如果不想以DllMain为入口点也可以,无非是改个名字。函数协议也可以有变化,如果你对参数毫不关心的话,甚至可以用void main()来作为Dll的入口点函数,不过链接的时候会给你警告,你的入口点函数不符合DllMain函数协议可能会出错。
自定义入口点的好处是可以极大降低生成的dll的体积。比如我用MT方式编译的无功能dll是68K,自定义入口点之后是4K。
坏处是不能用运行库的函数,因为没有初始化,没有链接进来。 这个吗?dll入口点 能想到的用处就是定义不同的入口对应不同的功能,方便不同版本做功能切换,不过用define宏控制也是一样,不太理解这个功能有什么好处。
对于编译完成的dll来说,入口就是入口,没有什么意义。 yes2 发表于 2023-8-11 09:28
以vs举例,其他的可能也大差不差。
你写一个动态库,一般来说入口点就是DllMain,编译器会自动链接SDK中的 ...
回答的不错,受教了。 本帖最后由 seeyou_shj 于 2023-8-11 10:20 编辑
以前写过一片关于dll文件的内容,很简单,不过似乎可以解答你的问题。去看看吧。用的是mingw编译器。
https://user.qzone.qq.com/37505515/infocenter
主要内容如下:
写一个简单的dll文件,内容如下(main.cpp):
extern "C" int sub(int a,int b){
return a-b;
}
extern "C" int add(int a,int b, int c){
return sub(a,b)+c;
}
编译:g++ -shared main.cpp -o main.dll,ok,得到main.dll文件了。
在python环境中测试一下,结果正常:
>>> import ctypes
>>> m = ctypes.cdll.LoadLibrary("d:/temp/main.dll")
>>> m.add(5,3,8)
10
only998 发表于 2023-8-11 08:29
能想到的用处就是定义不同的入口对应不同的功能,方便不同版本做功能切换,不过用define宏控制也是一样,不 ...
@only998
正好老兄在场,借机问个同类型的问题吧!
我的设计是这样的:
通过DLL(x64dbg的*.dp64)连接上之后,我外部*.exe能不能执行 DbgCmdExec(PAnsiChar(AnsiString('StepOver')));
我那个是*.dpr (生成x64dbg的*.dp64 【其实就是特种形态的DLL】)
我写把过程弄好之后,弄了一个导出函数。
library MoreTool;
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
{$WEAKLINKRTTI ON}
uses
Windows,
Messages,
vcl.Forms,
bridgemain in 'plugin\bridgemain.pas',
_plugins in 'plugin\_plugins.pas';
{$ALIGN 1}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CAST OFF}
{$IFDEF WIN64}
{$E dp64}
{$ELSE}
{$E dp32}
{$ENDIF}
var
SaveDLLProc: TDLLProc;
g_pluginHandle: THandle = 0;
g_hMenu: Cardinal = 0;
g_hMenuDisasm: Cardinal = 0;
g_Inst: Cardinal = 0;
g_hWnD: Cardinal = 0;
g_loadedname: array of PAnsiChar;
function ShellExecuteA(hWnd: hWnd; Operation, FileName, Parameters, Directory: PAnsiChar; ShowCmd: Integer): HINST; stdcall; external 'shell32.dll' name 'ShellExecuteA';
const
PLUGIN_NAME: PAChar = 'MoreTool';
PLUGIN_AUTH: PAChar = 'remek002';
PLUGIN_VERS: Integer = 01;
MENU_CALC = 1;
MENU_NOTEPAD = 2;
MENU_DISASM_CALC = 3;
MENU_DISASM_NOTEPAD = 4;
{$R MoreTool.res}
procedure RegisterInitProc(cbType: cbType; callbackInfo: Pointer); cdecl;
var
info: PPLUG_CB_INITDEBUG;
begin
ZeroMemory(@g_loadedname, SizeOf(g_loadedname));
info := PPLUG_CB_INITDEBUG(callbackInfo);
g_loadedname := info^.szFileName;
BridgeSettingSet('Last File', 'Last', g_loadedname);
end;
procedure RegisterMenuProc(cbType: cbType; callbackinfo: Pointer); cdecl;
var
info: PPLUG_CB_MENUENTRY;
begin
info := PPLUG_CB_MENUENTRY(callbackinfo);
case (info^.hEntry) of
MENU_CALC:
begin
ShellExecuteA(GuiGetWindowHandle, 'OPEN', 'calc.exe', '', 'C:\Windows\system32', SW_SHOWNORMAL);
end;
MENU_NOTEPAD:
begin
ShellExecuteA(GuiGetWindowHandle, 'OPEN', 'notepad.exe', '', 'C:\Windows\system32', SW_SHOWNORMAL);
end;
MENU_DISASM_CALC:
begin
ShellExecuteA(GuiGetWindowHandle, 'OPEN', 'calc.exe', '', 'C:\Windows\system32', SW_SHOWNORMAL);
end;
MENU_DISASM_NOTEPAD:
begin
ShellExecuteA(GuiGetWindowHandle, 'OPEN', 'notepad.exe', '', 'C:\Windows\system32', SW_SHOWNORMAL);
end;
end;
end;
function calc(argc: Integer; argv: PPAnsiChar): Boolean; cdecl;
begin
ShellExecuteA(GuiGetWindowHandle, 'OPEN', 'calc.exe', '', 'C:\Windows\system32', SW_SHOWNORMAL);
end;
function notepad(argc: Integer; argv: PPAnsiChar): Boolean; cdecl;
begin
ShellExecuteA(GuiGetWindowHandle, 'OPEN', 'notepad.exe', '', 'C:\Windows\system32', SW_SHOWNORMAL);
end;
function x_dbg_Plugininit(PlugInitInfo: PPLUG_INITSTRUCT): Boolean; cdecl;
begin
g_pluginHandle := PlugInitInfo^.pluginHandle; //Address: 0043E7DC
PlugInitInfo^.sdkVersion := PLUG_SDKVERSION;
PlugInitInfo^.PluginVersion := PLUGIN_VERS;
lstrcpyA(PlugInitInfo^.pluginName, PLUGIN_NAME);
_plugin_registercallback(g_pluginHandle, CB_MENUENTRY, RegisterMenuProc);
_plugin_registercallback(g_pluginHandle, CB_INITDEBUG, RegisterInitProc);
Result := True;
end;
procedure x_dbg_Pluginsetup(PlugSetupInfo: PPLUG_SETUPSTRUCT); cdecl;
begin
g_hMenu := PlugSetupInfo^.hMenu;
g_hMenuDisasm := PlugSetupInfo^.hMenuDisasm;
_plugin_menuaddentry(g_hMenuDisasm, MENU_DISASM_CALC, 'Open Calc');
_plugin_menuaddseparator(g_hMenuDisasm);
_plugin_menuaddentry(g_hMenuDisasm, MENU_DISASM_NOTEPAD, 'Open Notepad');
_plugin_menuaddentry(g_hMenu, MENU_CALC, 'Open Calc');
_plugin_menuaddseparator(g_hMenu);
_plugin_menuaddentry(g_hMenu, MENU_NOTEPAD, 'Open Notepad');
if not (_plugin_registercommand(g_pluginHandle, 'Calc', calc, false)) then
_plugin_logputs(' ErroR Registering The "Calc" command! ');
if not (_plugin_registercommand(g_pluginHandle, 'Notepad', notepad, false)) then
_plugin_logputs(' ErroR Registering The "Notepad" command! ');
// Add Plugin info
_plugin_logprintf('[***] %s Plugin v%i by %s '#10, PLUGIN_NAME, PLUGIN_VERS, PLUGIN_AUTH);
end;
function x_dbg_plugstop(): Boolean; cdecl;
begin
//
_plugin_unregistercallback(g_pluginHandle, CB_MENUENTRY);
_plugin_unregistercallback(g_pluginHandle, CB_INITDEBUG);
Result := True;
end;
procedure Super; stdcall;
begin
Application.MessageBox(PWideChar('我被调用啦!!!'), PWideChar('你好'), 0); ===>这句没问题被执行了!
DbgCmdExec(PAnsiChar(AnsiString('StepOver'))); ========》这句死活没动静!
end;
exports
Super, ============>导出了!
x_dbg_Plugininit name 'pluginit',
x_dbg_Pluginsetup name 'plugsetup',
x_dbg_plugstop name 'plugstop';
procedure DLLEntryPoint(dwReason: DWORD);
var
szPluginName: array of ACHAR;
begin
if (dwReason = DLL_PROCESS_DETACH) then
begin
lstrcatA(szPluginName, PLUGIN_NAME);
lstrcatA(szPluginName, ' Unloaded By DLL_PROCESS_DETACH');
OutputDebugStringA(szPluginName);
end;
if Assigned(SaveDLLProc) then
SaveDLLProc(dwReason);
end;
begin
g_Inst := HInstance;
SaveDLLProc := @DLLProc;
DLLProc := @DLLEntryPoint;
Application.MessageBox(PWideChar('执行成功'), PWideChar('你好'), 0);
end.
主程序 Project.exe中调用DLL的代码是:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls;
type
TForm2 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
uses
bridgemain, _plugins;
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject); {下面是调用的关键代码}
var
My: procedure; stdcall;
var
Hand: Cardinal;
begin
Hand := LoadLibrary('C:\Users\Administrator\Desktop\Mdebug32\x64dbg_2023-08-01\x64\plugins\MoreTool.dp64');
if Hand <> 0 then
begin
ShowMessage(Hand.ToString);
My := GetProcAddress(Hand, 'Super');
// DbgCmdExec(PAnsiChar(AnsiString('StepOver'))); 直接调用肯定完犊子!!!
end;
end;
end.
为什么呢? 不解? 冥界3大法王 发表于 2023-8-11 10:39
@only998
正好老兄在场,借机问个同类型的问题吧!
dp64依赖的是 x64dbg里的实现,我没深入研究过,崩溃的原因无非两点,一是dp64需要exe里的某些实现,你没有程序就崩溃。二是dp64依赖于其他x64dbg目录下的dll,你没有,也崩溃。注意你自己加载的话,工作目录跟x64dbg是不一样的。
我认为.dp64不可能脱离x64dbg的,如果想要单exe实现某些操作,直接调用系统函数更好一点。 seeyou_shj 发表于 2023-8-11 10:16
以前写过一片关于dll文件的内容,很简单,不过似乎可以解答你的问题。去看看吧。用的是mingw编译器。
ht ...
https://learn.microsoft.com/zh-cn/windows/win32/dlls/dllmain?redirectedfrom=MSDN
看看这个 感觉没什么用,dll加载卸载由系统调用的
页:
[1]
2