1.要创建一个Thunk Script 脚本
2。要创建一个32bit DLL
3.要利用32bit DLL来调用16bit DLL
然后用VC带的Thunk.exe来编译那个ThunkScript
用MASM来编译产生的汇编代码
---------------------------------------
32位程序调用16位DLL
如题,我也见过一些QT_Thunk的例子,但对各种参数类型的传递不很清楚,
试成功过无参数及整形参数的例子,但指针类型的参数一直失败,紧急求教
最好Mail给我例子,daixd@263.net
实际是我要在Delphi4中调用VC1.5生成的Dll
C的函数原形如
INT2 DllExport Init_search(char *sj_drivestr,char *ck_drivestr,char *basestr);
UINT2 DllExport Word_search(char *string,unsigned long search_result[],INT2 jsfs,char key);
等...
急,愿赠200分!
Keyes :
type
//Dos File header
DosFileHeader = record
ID: Word;
LengthMod: Word;
LengthDIV: Word;
Segments: Word;
ParagraphsHeader: Word;
MinHeader: Word;
MaxHeader: Word;
SPReg: Word;
CheckSumHeader: Word;
IPReg: Word;
CodeSeg: Word;
RelocTable: Word;
OverlayNumber: Word;
end;
//Windows File header
WindowsFileHeader = record
ID: longint;
Machine: Word;
NumberOfObjects: Word;
TimeDateStamp: DWord;
PointerToSymbolTable: LongInt;
NumberofSymbols: LongInt;
SizeOfOptionalHeader: Word;
Characteristics: Word;
//followed by advanced NT/Win95 Header (portable executable)
Magic: Word;
MajorVersion: Byte;
MinorVersion: Byte;
SizeOfCode: Longint;
SizeOfInitializedDate: Longint;
SizeOfUninitializedData: LongInt;
AddressOfEntryPoint: LongInt;
BaseOfCode: LongInt;
BaseOfData: LongInt;
ImageBase: LongInt;
SectionAlignment: LongInt;
FileAlignment: Longint;
OSMajor: Word;
OSMinor: Word;
UserMajor: Word;
UserMinor: Word;
OSMajorSub: Word;
OSMinorSub: Word;
Reserved1: LongInt;
SizeOfImage: Longint;
SizeOfHeader: Longint;
CheckSum: Longint;
Subsystem: word;
DLLCharacteristics: word;
SizeOfStackReserve: Longint;
SizeOfStackCommit: Longint;
SizeOfHeapReserve: longint;
SizeOfHeapCommit: Longint;
loaderFlags: Longint;
NumberofRVAandSizes: LongInt;
end;
//Entry-struct in object table
ObjectTableEntry = record
ObjectName: array[0..7] of Byte;
VirtualSize: Longint;
VirtualAddress: Longint;
SizeOfRawData: longInt;
PointerToRawData: longint;
PointerToRelocations: LongInt;
PointerToLineNumbers: LongInt;
NumberOfRelocations: Word;
NumberOfLineNumbers: Word;
Characteristics: LongInt;
end;
//Structure of export-table
ExportTableHeader = record
Characteristics: Longint;
TimeDateStamp: Longint;
MajorVersion: Word;
MinorVersion: Word;
Name: LongInt;
base: Longint;
NumberofFunctions: Longint;
NumberofNames: Longint;
pAddressofFunctions: Longint;
pAddressofNames: Longint;
pAddressOfNameOrdinals: Longint;
end;
//declarations for undocumented functions
fBeep = function (Frq, Time: Longint):boolean; stdcall;
fVxDCall = function (Service: Longint; Ax, CX: Longint): Longint; stdcall;
fLoadLibrary16 = function (LibName: PChar): THandle; stdcall;
fFreeLibrary16 = function (Handle: integer): integer; stdcall;
fGetProcAddress16 = function (handle: integer; ProcName: PChar): pointer; stdcall;
function GetProcAddress32(LibName: PChar; Ordinal: integer): pointer;
procedure QT_Thunk; cdecl; external kernel32 name 'QT_Thunk';
function GetProcAddress32(LibName: PChar; Ordinal: integer): pointer;
var
AddressOfFunction: ^Longint;
VirtualFunctionAddress: ^Longint;
WindowsHeaderOffset: ^Word;
ModuleHandle: THandle;
i: integer;
ObjectName: PChar;
FirstObjectAddress: Longint;
WindowsHeader: ^WindowsFileHeader;
ObjectEntry: ^ObjectTableEntry;
ExportObject: ^ObjectTableEntry;
ExportTable: ^ExportTableHeader;
begin
//Get module address (virtual) in memory
ModuleHandle := GetModuleHandle(LibName);
WindowsHeaderOffset := ptr(ModuleHandle +$3C);
WindowsHeader := ptr(ModuleHandle + WindowsHeaderOffset^);
//find export table
for i := 0 to WindowsHeader^.NumberofObjects-1 do
begin
FirstObjectAddress := ModuleHandle + WindowsHeaderOffset^ + SizeOf(WindowsHeader^) +
WindowsHeader^.NumberofRVAandSizes*8 + i*SizeOf(ObjectEntry^);
ObjectName := ptr(FirstObjectAddress);
if ObjectName = '.edata' then
begin
ExportObject := ptr(FirstObjectAddress);
ExportTable := ptr(ModuleHandle + ExportObject^.VirtualAddress);
end;
end;
//getting function address
VirtualFunctionAddress := ptr( ModuleHandle + ExportTable^.pAddressOfFunctions +
(Ordinal-ExportTable^.Base)*4);
//...and back
AddressOfFunction := ptr(WindowsHeader^.ImageBase + VirtualFunctionAddress^);
GetProcAddress32 := AddressOfFunction;
end;
amo (1999-10-25 11:03:39)
补充对Keyes的代码的说明:
The intention of this posting is to show a way of how to access 16 bit
DLLs out of an application developed in Delphi 2. A few days ago i
posted a message in delphi.misc to show the usage of undocumented
functions inside Kernel32.dll. Especially there are four of interest:
LoadLibrary16, GetProcAddress16, FreeLibrary16 and VxDCall0. With the
help of these functions, you can load and free 16bit libraries and get
the virtual address of a procedure inside a dll.
But there are some problems: kernel32 does not export undocumented
functions by name or ordinal. The only way to solve this was to read
and understand the internal PE(portable executable) format
specification. The PE format is used by 32bit apps and dlls. By
examining this format, you will find an export table with the absolute
offset of each function inside. Combined with the virtual module
address in memory, you get the virtual starting point of an
undocumented function. This does the function GetProcAdress32.
The next problem: 16bit functions/apps are using a different kind of
addressing (segment:offset) and have their own address space/stack
inside Win95, which "emulates" a 16bit os. To call a 16bit function
out of a 32bit application, you have to "build" a 16bit stack and to
do some other work ;-) . This does a kernel32 function named
'QT_Thunk'. With the help of some lines of inline assembler, you push
your arguments on the stack, push the virtual address of your 16bit
function in the register edx and call QT_Thunk. The return values can
be found in several registers. The example uses the
GetFreeSystemResources inside (the 16bit) user.exe and works fine.
Some comments: This source is free but without any guarantees! I would
like to get responses about the implementation of my code in yours.
The implementation of the thunk mechanism inside the asm statement was
taken from an example of Tempest Software, but i do not accept their
copyright, since their piece of code does *not* work and uses no
special algorithms (only some WIN API calls)! The information about
accessing undocumented functions was taken from Andrew Schulmans
"Undocumented Windows" and "Unautherized Windows". Great books! If you
have problems with getting this code to run mail me, i will send you a
copy of my complete source as attachment.
dxd (1999-10-27 9:27:20)
谁能写的明白些?
如是C函数INT2 DllExport Init_search(char *sj_drivestr,char *ck_drivestr,char *basestr);的Delphi描述如下
var
hInst16: THandle;
GFSR: Pointer;
function D16_HR_init_search(IndexDir,CkDir,BaseDir:string):Integer;
var
pp:DWORD;
p:Pointer; fm:THandle;
ThunkTrash: array[0..$20] of Word;
ans:WORD;
iDir,cDir,bDIr:PChar;
hi1,hi2,hi3,lo1,lo2,lo3:WORD;
begin
Result:=-1;
if Win32Platform = VER_PLATFORM_WIN32_NT then Exit;
StrPcopy( iDir,IndexDir );
StrPcopy( cDir,CKDir );
StrPcopy( bDir,BaseDir );
ThunkTrash[0] := hInst16;
hInst16 := LoadLibrary16('SAPI16.DLL');
if hInst16 < 32 then
raise Exception.Create('Cannot load SAPI16.DLL');
// FreeLibrary16(hInst16);
GFSR := GetProcAddress16(hInst16, 'HR_init_search');
if GFSR = nil then
raise Exception.Create('Get address Error of HR_init_search');
hi1 := WORD((DWORD(iDir) shr 16) and $ffff );
lo1 := WORD(DWORD(iDir) and $ffff );
hi2 := WORD((DWORD(CDir) shr 16) and $ffff );
lo2 := WORD(DWORD(CDir) and $ffff );
hi3 := WORD((DWORD(BDir) shr 16) and $ffff );
lo3 := WORD(DWORD(BDir) and $ffff );
asm //Thunk down to USER.EXE
push hi1
push lo1
push hi2
push lo2
push hi3
push lo3
mov edx, GFSR { load 16-bit procedure pointer }
call QT_Thunk { call thunk }
mov ans, ax { save the result }
end;
{ Free the library }
FreeLibrary16(hInst16);
if ans > 0 then Result:=0;
end;
执行总是出错,请诊治!
Another_eYes (2000-9-4 21:48:09)
瞎猜的:
32位的call指令将32位返回地址地址压栈. 而16位程序取参数一般是从[bp-2]开始的
而此时真正的参数应当在[ebp-4]位置, 故出错.
所以我猜想可否call指令替换成
PUSH ESP // ESP能直接压栈吗? 忘了
MOV EBP, ESP
ADD EBP,2
JMP QT_Thunk
Another_eYes (2000-9-4 21:55:48)
错了错了, 记错了. 呵呵 ESP是堆栈寄存器不是指令寄存器.
而且上述理解有误.
问题应当出在返回后的堆栈上. CALL时32位压栈, 16位程序的RET只出栈了16位,
因此返回后堆栈需要调整
CALL后加一句
POP DX (或者 ADD SP, 2)
试试