当前位置:主页>仓库管理软件> 列表

装载DLL时如何改隐式调用为显式?

财务软件版1楼: external kernel32 index 93; 对于这种基于索引导出的函数,如何改成显式的?

2楼: 这种只有编号输出的DLL函数,应该也可以用GetProcAddress定位的,第二个参数直接传编号即可,比如GetProcAddress(x, PChar(36)),以上答案仅供参考.. 如商贸财神进销存软

3楼: 查过书才知道,对于一些未公开函数,用GetProcAddress()无法定位其地址,因为微软不希望
你调用它,解决方法之一,就是自己用程序来定位,俺试着写了一个,98还没测试,XP测试通过:

unit NewGetProcAddress;

interface

uses Windows;

// GetProcAddress自由版, ^^
function GetProcAddress_lmz(hModule: THandle; lpProcName: PChar): Pointer;

implementation

// 按照序号定位DLL函数
function GetProcAddress_FromExportOrdinal(pNTHdr: PImageNtHeaders; Ordinal: DWord): Pointer;
var
pExpDir: PImageExportDirectory;
pFunctionArray: PDWord;
ImageBase: DWord;
ExportDirSize: DWord;
szForwardedModule: array[0..MAX_PATH] of Char;
pszForwardedFunctionName: PChar;


hForwardedMod: THandle;
begin
Result := nil;

// 导出表长度
ExportDirSize := pNTHdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if (ExportDirSize = 0) then Exit;

// 映像基地址
ImageBase := pNTHdr.OptionalHeader.ImageBase;

// 导出表地址
pExpDir := PImageExportDirectory(
pNTHdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress +
ImageBase);

// 函数地址表
pFunctionArray := PDWord(ImageBase + DWord(pExpDir.AddressOfFunctions));

// 编号超出范围
if (pExpDir.NumberOfFunctions <= (Ordinal - pExpDir.Base)) then Exit;

// 函数相对地址
Result := PPointer(DWord(pFunctionArray) + (Ordinal - pExpDir.Base) * SizeOf(DWord))^;

// 函数绝对地址
if (Result <> nil) then Inc(PByte(Result), ImageBase);

// 是否转交函数
if (DWord(Result) >= DWord(pExpDir)) and (DWord(Result) < (DWord(pExpDir) + ExportDirSize)) then
begin
// 解析"转交串"


lstrcpy(szForwardedModule, Result);
pszForwardedFunctionName := @szForwardedModule;
while (pszForwardedFunctionName^ <> ''.'') do Inc(pszForwardedFunctionName);
pszForwardedFunctionName^ := #0;
Inc(pszForwardedFunctionName);

// 定位转交函数
hForwardedMod := GetModuleHandle(szForwardedModule);
Result := GetProcAddress_lmz(hForwardedMod, pszForwardedFunctionName);
end;
end;

// 按照名字定位DLL函数
function GetProcAddress_FromExportName(pNTHdr: PImageNtHeaders; lpszProcName: PChar): Pointer;
var
pExpDir: PImageExportDirectory;
ImageBase: DWord;
pNamesArray: PDWord;
pNameOrdinalsArray: PWord;
pszCurName: PChar;
NameOrdinal, J: DWord;
begin
Result := nil;

// 无输出函数
if (pNTHdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = 0) then Exit;

// 映像基地址
ImageBase := pNTHdr.OptionalHeader.ImageBase;

// 输出表地址
pExpDir := PImageExportDirectory(
pNTHdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress +
ImageBase);

// 无名字输出
if (pExpDir.NumberOfNames = 0) then Exit;

// 名字字串数组
pNamesArray := PDWord(ImageBase + DWord(pExpDir.AddressOfNames));

// 名字编号数组
pNameOrdinalsArray := PWord(ImageBase + DWord(pExpDir.AddressOfNameOrdinals));

// 按名字查找
for J := 0 to pExpDir.NumberOfNames - 1 do
begin
pszCurName := PChar(ImageBase + PDWord(DWord(pNamesArray) + SizeOf(DWord) * J)^);
if (lstrcmp(pszCurName, lpszProcName) = 0) then Break;
end;
if (J = pExpDir.NumberOfNames) then Exit;

// 按编号定位
NameOrdinal := PWord(DWord(pNameOrdinalsArray) + SizeOf(Word) * J)^;
Result := GetProcAddress_FromExportOrdinal(pNTHdr, NameOrdinal + pExpDir.Base);
end;

// GetProcAddress自由版, ^^
function GetProcAddress_lmz(hModule: THandle; lpProcName: PChar): Pointer;
var
DosHeaderPt: PImageDosHeader;

NtHeadersPt: PImageNtHeaders;
begin
Result := nil;

// 模块映像基地址
if (hModule = 0) then Exit;
DosHeaderPt := PImageDosHeader(hModule);

// 效验 DOS 文件头
if (DosHeaderPt.e_magic <> IMAGE_DOS_SIGNATURE) then Exit;
NtHeadersPt := PImageNtHeaders(Integer(DosHeaderPt) + DosHeaderPt._lfanew);

// 效验 PE 文件头
if (NtHeadersPt.Signature <> IMAGE_NT_SIGNATURE) then Exit;

// 名字串还是编号
if (HiWord(DWord(lpProcName)) = 0) then
Result := GetProcAddress_FromExportOrdinal(NtHeadersPt, DWord(lpProcName))
else
if (IsBadStringPtr(lpProcName, 0) = False) then
Result := GetProcAddress_FromExportName(NtHeadersPt, lpProcName);
end;

end.

4楼: XP 测试例子:

procedure TForm1.Button1Click(Sender: TObject);
type
TMessageBox = function (hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall;
var
x: TMessageBox;
begin
// x := GetProcAddress_lmz(GetModuleHandle(user32), PChar(476 + 1));


// 在我这里,MessageBoxA的编号是476,不同版本的user32.dll,编号可能变化

x := GetProcAddress_lmz(GetModuleHandle(user32), ''MessageBoxA'');
if (@x <> nil) then x(Self.Handle, ''GetProcAddress_lmz.. '', ''测试'', MB_OK);
end;

5楼: 未公开函数最好不要使用,谁知道微软什么时候修改掉它。2000和XP中就有很多的未公开函数是不同的!

6楼: 98 测试例子:

procedure TForm1.Button1Click(Sender: TObject);
type
Twvsprintf = function (Output: PAnsiChar; Format: PAnsiChar; arglist: va_list): Integer; stdcall;
var
x: Twvsprintf;
OutPutBuf: array[0..50] of Char;
InputList: array[1..2] of DWORD;
begin
x := GetProcAddress_lmz(GetModuleHandle(kernel32), PChar(16));
if (@x = nil) then Exit;

InputList[1] := DWord(PChar(''小麻''));
InputList[2] := 6;
x(OutPutBuf, ''我是%s,今年%d岁了..'', @InputList);

ShowMessage(OutPutBuf);
end;

财务软件版7楼: GetProcAddress
The GetProcAddress function retrieves the address of an exported function or variable from the specified dynamic-link library (DLL).

FARPROC GetProcAddress(
HMODULE hModule, // handle to DLL module
LPCSTR lpProcName // function name
);
Parameters
hModule
[in] Handle to the DLL module that contains the function or variable. The LoadLibrary or GetModuleHandle function returns this handle.
lpProcName
[in] Pointer to a null-terminated string containing the function or variable name, or the function''s ordinal value. If this parameter is an ordinal value, it must be in the low-order word; the high-order word must be zero.
Return Values
If the function succeeds, the return value is the address of the exported function or variable.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

8楼: 为什么要自己写一个GetProcAddress(), 俺已经说过了, 楼上的兄弟看帖不认真.. [:(]

9楼: OK.
http://www.138soft.com/html/ssc/1/2/16.htm

我现在还是直接使用index.里面用到以下函数.
function LoadLibrary16(LibraryName: PChar): THandle; stdcall; external kernel32 index 35;


procedure FreeLibrary16(HInstance: THandle); stdcall; external kernel32 index 36;
function GetProcAddress16(Hinstance: THandle; ProcName: PChar): Pointer; stdcall; external kernel32 index 37;

procedure GetpWin16Lock(pWin16Lock:PDWORD);stdcall; external kernel32 index 93;
procedure EnterSysLevel(lock:DWORD);stdcall;external kernel32 index 97;
procedure LeaveSysLevel(lock:DWORD);stdcall;external kernel32 index 98;

因为这些函数在Win2000下也存在.所以隐式也不会报错.

10楼: 哦, Win2k 的 Kernel32.dll 中也存在这些序号的输出函数, 所以仅仅装载而不调用是不会出错的, 嗯嗯.. [:D]

11楼: 当然仔细看了, 只是对你的答案做一下补充而已

12楼: 多人接受答案了。 如免费销售管理软件