首页  编辑  

32位程序调用16位DLL

Tags: /超级猛料/DLL.动态链接库/   Date Created:

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)

试试