精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>C/C++>>技术精解:内存、进程、线程等>>Win32程序调用16位DLL里的API函数

主题:Win32程序调用16位DLL里的API函数
发信人: wenbobo(灌了拂衣去)
整理人: wenbobo(2002-12-06 23:30:34), 站内信件
文章虽不是原创,至少也是我翻译的,请大家转载时注明出处。 
原作者:Sergey Karyshev([email protected]
原文发表于:www.codeguru.com 


Windows 95 最后的秘密暴光了! 

一个关于Windows95问得最多的问题是“资源管理器是如何得到系统资源使用状况的”? 

微软文档表明GetFreeSystemResources函数在Win32中被停止使用了.Win32文档也说现在系统资源实际上是无限.但是资源管理器的关于对话框提示这种说法是不恰当的(至少对Windows95)。我还没有测验过Windows98但我相信文档对于WindowsNT来说是恰当.但是,对于Windows95,他们的文档肯定搞错了.[main注:其实95/OSR2/98/se/me都一样] 

16位模块USER.EXE在Windows95中仍然存在,并且16位的应用程序能通过16位的函数GetFreeSystemResources来找到系统资源信息.那样,为什么资源管理器(或者任何32位应用程序)不能也这样调用呢? 



下面代码片段展示了Win32程序如何调用16位DLL里的API函数。请注意GetK32ProcAddress函数由Andrew Schulman的“Unauthorized Windows 95 Update”提供。为了满足你的好奇心,这里提供这个函数的头文件和实现部分的链接: 

http://ftp.uni-mannheim.de/info/OReilly/windows/win95.update/k32exp.c  
http://ftp.uni-mannheim.de/info/OReilly/windows/win95.update/k32exp.h  
[main注:我会在后面附上这两个文件的] 

(因为k32exp.c是作为一独立模块的,我猜测它是被版权保护的) 

WORD GetFreeSystemResources(WORD type)  
{  
 //Decarations  "c" style  
 typedef HINSTANCE (WINAPI* LOADLIB16)(char*);  
 typedef LONG (WINAPI* GETPROC16)(HINSTANCE, LPCSTR);  
 typedef BOOL (WINAPI* FREELIB16)(HINSTANCE);  
 FARPROC QT_Thunk;  
   
 LOADLIB16 pLoadLib16;  
 GETPROC16 pGetProc16;  
 FREELIB16 pFreeLib16;  
 HINSTANCE hInst;  
 DWORD pGetRes;  
 WORD user_fsr;  
 WORD _type;  
 HMODULE hKernel;  
  
 //Usuall Windows API calls  
 hKernel = GetModuleHandle("KERNEL32");  
 QT_Thunk = GetProcAddress(hKernel, "QT_Thunk");  
  
 //Andrew Schulman's   
 pLoadLib16 = (LOADLIB16) GetK32ProcAddress(LOADLIBRARY16_ORD);  
 pGetProc16 = (GETPROC16) GetK32ProcAddress(GETPROCADDRESS16_ORD);  
 pFreeLib16 = (FREELIB16) GetK32ProcAddress(FREELIBRARY16_ORD);  
  
 //Usuall for "c"-style calls - by pointer to function   
 hInst = (*pLoadLib16)("user");  
 (*pFreeLib16)(hInst);  
 pGetRes = (*pGetProc16)(hInst,"GetFreeSystemResources");  
  
 //How to call 16-bit dll API from 32-bit .exe using QT_Thunk function  
 _type = type;  
 if (pGetRes)  
 _asm  
 {     
  push    _type  
  mov     edx, [pGetRes]   
  call    QT_Thunk   
  mov     [user_fsr], ax  
 }  
 return user_fsr;  
}  

文中的演示是一个要取得Windows95的剩余系统资源的控制台程序。可以简单的从控制台编译它。 

你怎么知道Windows95资源管理器使用16位的USER.EXE得到剩余系统资源的?只需要请求你的黑客好朋友在USER.EXE让GetFreeSystemResources函数返回0然后再看看资源管理器显示的剩余系统资源是多少!在我的4.00.950版本的USER.EXE中,GetFreeSystemResources从偏移地址0x444FF开始. 
[main注:用IDA修改,选择patch功能,打入汇编代码ret 0] 



[main注:方便大家,我把相关文件附在这里] 

[这是主程序] 
#include <windows.h> 
#include "k32exp.h" 

#include "stdio.h" //for printf only 


// From 16-bit windows.h 
#define GFSR_SYSTEMRESOURCES 0 
#define GFSR_GDIRESOURCES 1 
#define GFSR_USERRESOURCES 2 

//Forward declaration - usual for "c" 
WORD GetFreeSystemResources(WORD type); 

//It is console win app 
int main( int argc, char *argv[ ], char *envp[ ] ) 

WORD lSysRes  = GetFreeSystemResources(GFSR_SYSTEMRESOURCES); 
WORD lGdiRes  = GetFreeSystemResources(GFSR_GDIRESOURCES); 
WORD lUsrRes = GetFreeSystemResources(GFSR_USERRESOURCES); 

printf("System resource: %d%%\n", lSysRes); 
printf("GDI resource: %d%%\n", lGdiRes); 
printf("User resource: %d%%\n", lUsrRes); 

return 0; 

    
//We need this pragma to make a compiler even don't think about to modify a code in release mode 
#pragma optimize ("", off)  
WORD GetFreeSystemResources(WORD type) 

//SAFE macro just returns 99 if something goes wrong (say under NT) 
#define DUMMY_RES 99 
#define SAFE(a) if(!(a)) return DUMMY_RES 

//Decarations  "c" style 
typedef HINSTANCE (WINAPI* LOADLIB16)(char*); 
typedef LONG (WINAPI* GETPROC16)(HINSTANCE, LPCSTR); 
typedef BOOL (WINAPI* FREELIB16)(HINSTANCE); 
FARPROC QT_Thunk; 

LOADLIB16 pLoadLib16; 
GETPROC16 pGetProc16; 
FREELIB16 pFreeLib16; 
HINSTANCE hInst; 
DWORD pGetRes; 
WORD user_fsr; 
WORD _type; 
HMODULE hKernel; 

//Usuall Windows API calls 
SAFE( hKernel = GetModuleHandle("KERNEL32")); 
SAFE( QT_Thunk = GetProcAddress(hKernel, "QT_Thunk")); 

//Andrew Schulman's  
SAFE( pLoadLib16 = (LOADLIB16) GetK32ProcAddress(LOADLIBRARY16_ORD)); 
SAFE( pGetProc16 = (GETPROC16) GetK32ProcAddress(GETPROCADDRESS16_ORD)); 
SAFE( pFreeLib16 = (FREELIB16) GetK32ProcAddress(FREELIBRARY16_ORD)); 

//Usuall for "c"-style calls - by pointer to function  
SAFE( hInst = (*pLoadLib16)("user")); 
(*pFreeLib16)(hInst); 
SAFE( pGetRes = (*pGetProc16)(hInst,"GetFreeSystemResources")); 

//How to call 16-bit dll API from 32-bit .exe using QT_Thunk function 
/*Actually it is   

__asm mov     edx, *pGetRes 
return (*QT_Thunk)(type); 

but compiler may produce a differnt code. 
To make QT_Thunk work we need exact code bellow 
*/ 

_type = type;//for inline asm only 
if (pGetRes) 
_asm 
{   
push    _type 
mov     edx, [pGetRes]  
call    QT_Thunk  
mov     [user_fsr], ax 

return user_fsr; 


/*There is another approach in MSVC documentation - "Thunk Compiler" chapter. 
I tried to learn about "Thunk Compiler" several times  and finally understood nothing.*/ 

#undef DUMMY_RES 
#undef SAFE 

#pragma optimize ("", on) 



[这就是前面提到的引用的代码] 
[头文件] 
/*  
K32EXP.H -- Get32ProcAddress 
Win32 code to import by ordinal from KERNEL32.DLL in Windows 95 

See K32EXP.C for more information 
*/ 

// KERNEL32.1 through KERNEL32.9 are all VxDCall 
#define VXDCALL_ORD                 1 

// found these by examining RUNDLL32.EXE 
#define LOADLIBRARY16_ORD           35 
#define FREELIBRARY16_ORD           36 
#define GETPROCADDRESS16_ORD        37 

// found these by examining WOW32.DLL 
// actually, these are documented: see GENTHUNK.TXT ("Windows NT 
// Generic Thunk Overview") and WOWNT32.H in Microsoft's Win32 SDK 
#define WOWCallback16_ORD           54                       
#define WOWCallback16Ex_ORD         55                       
#define WOWGetVDMPointer_ORD        56                       
#define WOWHandle32_ORD             57                       
#define WOWHandle16_ORD             58                       
#define WOWGlobalAlloc16_ORD        59                       
#define WOWGlobalLock16_ORD         60                       
#define WOWGlobalUnlock16_ORD       61                       
#define WOWGlobalFree16_ORD         62                       
#define WOWGlobalAllocLock16_ORD    63                       
#define WOWGlobalUnlockFree16_ORD   64                       
#define WOWGlobalLockSize16_ORD     65                       
#define WOWYield16_ORD              66                       
#define WOWDirectedYield16_ORD      67                       
#define WOWGetVDMPointerFix_ORD     68                       
#define WOWGetVDMPointerUnfix_ORD   69                       
#define WOW32_1_ORD                 70 

// found these by examining NTDLL.DLL (Win95) 
#define RtlLargeIntegerAdd_ORD              72  
#define RtlEnlargedIntegerMultiply_ORD      73  
#define RtlEnlargedUnsignedMultiply_ORD     74  
#define RtlEnlargedUnsignedDivide_ORD       75  
#define RtlExtendedLargeIntegerDivide_ORD   76  
#define RtlExtendedMagicDivide_ORD          77  
#define RtlExtendedIntegerMultiply_ORD      78  
#define RtlLargeIntegerShiftLeft_ORD        79  
#define RtlLargeIntegerShiftRight_ORD       80  
#define RtlLargeIntegerArithmeticShift_ORD  81  
#define RtlLargeIntegerNegate_ORD           82  
#define RtlLargeIntegerSubtract_ORD         83  
#define RtlConvertLongToLargeInteger_ORD    84  
#define RtlConvertUlongToLargeInteger_ORD   85  

#define GETPWIN16LOCK_ORD           93 
#define ENTERSYSLEVEL_ORD           97 
#define LEAVESYSLEVEL_ORD           98 

DWORD WINAPI GetK32ProcAddress(int ord); 

// VxDCall is probably the most important undocumented Win32 API 
DWORD (WINAPI *VxDCall)(DWORD srvc, DWORD eax, DWORD ecx); 

// Walking VxD chain shows that these are the VxDs that provide 
// Win32 services 
#define VMM_ID          0x0001             // 41 services 
#define REBOOT_ID       0x0009             // 2 
#define VNETBIOS_ID     0x0014             // 2 
#define VWIN3 

[实现部分] 
/* 
K32EXP.C -- Get32ProcAddress 
Win32 code to import by ordinal from KERNEL32.DLL in Windows 95 

After Andrew Schulman wrote Unauthorized Windows 95 (IDG Books, 1994), KERNEL32.DLL 
stopped exporting undocumented Win32 functions such as VxDCall() and 
GetpWin16Lock() by name. The functions discussed in *Unauthorized* 
continue to be exported by ordinal (for example, VxDCall is 
KERNEL32.1 and GetpWin16Lock is KERNEL.93). However, KERNEL32 does 
not allow imports by ordinal (Message from debug version: 
"GetProcAddress: kernel32 by id not supported"). 

This module provides GetK32ProcAddress() to support import by ordinal 
from KERNEL32. There's nothing undocumented in here, except for the 
ordinal numbers themselves. GetModuleHandle() returns the address of 
the executable image (see Matt Pietrek in *Microsoft Systems Journal*, 
September 1995, p. 20), and the image is documented in the PE (Portable 
Executable) file format. 
*/  
  
#include <windows.h> 
#include "k32exp.h" 

#define ENEWHDR     0x003CL         /* offset of new EXE header */ 
#define EMAGIC      0x5A4D          /* old EXE magic id:  'MZ'  */ 
#define PEMAGIC     0x4550          /* NT portable executable */ 

#define GET_DIR(x)  (hdr->OptionalHeader.DataDirectory[x].VirtualAddress) 
    
DWORD  WINAPI GetK32ProcAddress(int ord) 

    static HANDLE hmod = 0; 
    IMAGE_NT_HEADERS *hdr; 
    IMAGE_EXPORT_DIRECTORY *exp; 
    DWORD *AddrFunc; 
    WORD enewhdr, *pw; 
    int did_load = 0; 
    BYTE *moddb; 

    if (hmod == 0)      // one-time static init 
        hmod = GetModuleHandle("KERNEL32"); 
    if (hmod == 0)      // still 
        return 0; 
     
    moddb = (BYTE *) hmod; 
    pw = (WORD *) &moddb[0]; 
    if (*pw != EMAGIC)               
        return 0; 
    pw = (WORD *) &moddb[ENEWHDR]; 
    enewhdr = *pw; 
    pw = (WORD *) &moddb[enewhdr]; 
    if (*pw != PEMAGIC)              
        return 0; 
    hdr = (IMAGE_NT_HEADERS *) pw; 
     
    // Note: offset from moddb, *NOT* from hdr! 
    exp = (IMAGE_EXPORT_DIRECTORY *) (((DWORD) moddb) + 
        ((DWORD) GET_DIR(IMAGE_DIRECTORY_ENTRY_EXPORT))); 
    AddrFunc = (DWORD *) (moddb + (DWORD) exp->AddressOfFunctions); 

    // should verify that e.g.: 
    // GetProcAddress(hmod, "VirtualAlloc") == GetK32ProcAddress(710); 
     
    ord--;  // table is 0-based, ordinals are 1-based 
    if (ord < (int) exp->NumberOfFunctions) 
        return ((DWORD) (moddb + AddrFunc[ord])); 
    else 
        return 0; 





----
█◣◢█
◢█◤
◢█◤
█◤◥█  

[关闭][返回]