431 lines
12 KiB
C
431 lines
12 KiB
C
/*
|
|
* Win32 ordinal only exported functions
|
|
*
|
|
* Copyright 1997 Marcus Meissner
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "thread.h"
|
|
#include "winerror.h"
|
|
#include "heap.h"
|
|
#include "selectors.h"
|
|
#include "miscemu.h"
|
|
#include "winnt.h"
|
|
#include "module.h"
|
|
#include "callback.h"
|
|
#include "debug.h"
|
|
#include "stddebug.h"
|
|
|
|
extern THDB *pCurrentThread;
|
|
extern PDB32 *pCurrentProcess;
|
|
|
|
/**********************************************************************
|
|
* _KERNEL32_88
|
|
*/
|
|
DWORD
|
|
WOW32_1(DWORD x,DWORD y) {
|
|
fprintf(stderr,"WOW32_1(0x%08lx,0x%08lx), stub!\n",x,y);
|
|
return 0;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* WOWGetVDMPointer (KERNEL32.55)
|
|
* Get linear from segmented pointer. (MSDN lib)
|
|
*/
|
|
LPVOID
|
|
WOWGetVDMPointer(DWORD vp,DWORD nrofbytes,BOOL32 protected) {
|
|
/* FIXME: add size check too */
|
|
fprintf(stdnimp,"WOWGetVDMPointer(%08lx,%ld,%d)\n",vp,nrofbytes,protected);
|
|
if (protected)
|
|
return PTR_SEG_TO_LIN(vp);
|
|
else
|
|
return DOSMEM_MapRealToLinear(vp);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* WOWGetVDMPointerFix (KERNEL32.55)
|
|
* Dito, but fix heapsegment (MSDN lib)
|
|
*/
|
|
LPVOID
|
|
WOWGetVDMPointerFix(DWORD vp,DWORD nrofbytes,BOOL32 protected) {
|
|
/* FIXME: fix heapsegment */
|
|
fprintf(stdnimp,"WOWGetVDMPointerFix(%08lx,%ld,%d)\n",vp,nrofbytes,protected);
|
|
return WOWGetVDMPointer(vp,nrofbytes,protected);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* WOWGetVDMPointerUnFix (KERNEL32.56)
|
|
*/
|
|
void
|
|
WOWGetVDMPointerUnfix(DWORD vp) {
|
|
fprintf(stdnimp,"WOWGetVDMPointerUnfix(%08lx), STUB\n",vp);
|
|
/* FIXME: unfix heapsegment */
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* _KERNEL32_18 (KERNEL32.18)
|
|
* 'Of course you cannot directly access Windows internal structures'
|
|
*/
|
|
|
|
DWORD
|
|
_KERNEL32_18(DWORD processid,DWORD action) {
|
|
PDB32 *process;
|
|
TDB *pTask;
|
|
|
|
action+=56;
|
|
fprintf(stderr,"KERNEL32_18(%ld,%ld+0x38)\n",processid,action);
|
|
if (action>56)
|
|
return 0;
|
|
if (!processid) {
|
|
process=pCurrentProcess;
|
|
/* check if valid process */
|
|
} else
|
|
process=(PDB32*)pCurrentProcess; /* decrypt too, if needed */
|
|
switch (action) {
|
|
case 0: /* return app compat flags */
|
|
pTask = (TDB*)GlobalLock16(process->task);
|
|
if (!pTask)
|
|
return 0;
|
|
return pTask->compat_flags;
|
|
case 4: /* returns offset 0xb8 of process struct... dunno what it is */
|
|
return 0;
|
|
case 8: /* return hinstance16 */
|
|
pTask = (TDB*)GlobalLock16(process->task);
|
|
if (!pTask)
|
|
return 0;
|
|
return pTask->hInstance;
|
|
case 12:/* return expected windows version */
|
|
pTask = (TDB*)GlobalLock16(process->task);
|
|
if (!pTask)
|
|
return 0;
|
|
return pTask->version;
|
|
case 16:/* return uncrypted pointer to current thread */
|
|
return (DWORD)pCurrentThread;
|
|
case 20:/* return uncrypted pointer to process */
|
|
return (DWORD)process;
|
|
case 24:/* return stdoutput handle from startupinfo */
|
|
return (DWORD)(process->env_db->startup_info->hStdOutput);
|
|
case 28:/* return stdinput handle from startupinfo */
|
|
return (DWORD)(process->env_db->startup_info->hStdInput);
|
|
case 32:/* get showwindow flag from startupinfo */
|
|
return (DWORD)(process->env_db->startup_info->wShowWindow);
|
|
case 36:{/* return startup x and y sizes */
|
|
LPSTARTUPINFO32A si = process->env_db->startup_info;
|
|
DWORD x,y;
|
|
|
|
x=si->dwXSize;if (x==0x80000000) x=0x8000;
|
|
y=si->dwYSize;if (y==0x80000000) y=0x8000;
|
|
return (y<<16)+x;
|
|
}
|
|
case 40:{/* return startup x and y */
|
|
LPSTARTUPINFO32A si = process->env_db->startup_info;
|
|
DWORD x,y;
|
|
|
|
x=si->dwX;if (x==0x80000000) x=0x8000;
|
|
y=si->dwY;if (y==0x80000000) y=0x8000;
|
|
return (y<<16)+x;
|
|
}
|
|
case 44:/* return startup flags */
|
|
return process->env_db->startup_info->dwFlags;
|
|
case 48:/* return uncrypted pointer to parent process (if any) */
|
|
return (DWORD)process->parent;
|
|
case 52:/* return process flags */
|
|
return process->flags;
|
|
case 56:/* unexplored */
|
|
return 0;
|
|
default:
|
|
fprintf(stderr,"_KERNEL32_18:unknown offset (%ld)\n",action);
|
|
return 0;
|
|
}
|
|
/* shouldn't come here */
|
|
}
|
|
|
|
/***********************************************************************
|
|
* _KERNEL32_52 (KERNEL32.52)
|
|
* FIXME: what does it really do?
|
|
*/
|
|
VOID
|
|
_KERNEL32_52(DWORD arg1,CONTEXT *regs) {
|
|
fprintf(stderr,"_KERNE32_52(arg1=%08lx,%08lx)\n",arg1,EDI_reg(regs));
|
|
|
|
EAX_reg(regs) = (DWORD)WIN32_GetProcAddress16(EDI_reg(regs),"ThkBuf");
|
|
|
|
fprintf(stderr," GetProcAddress16(\"ThkBuf\") returns %08lx\n",
|
|
EAX_reg(regs)
|
|
);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* GetPWinLock (KERNEL32) FIXME
|
|
* get mutex? critical section for 16 bit mode?
|
|
*/
|
|
VOID
|
|
GetPWinLock(CRITICAL_SECTION **lock) {
|
|
static CRITICAL_SECTION plock;
|
|
fprintf(stderr,"GetPWinlock(%p)\n",lock);
|
|
*lock = &plock;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* _KERNEL32_43 (KERNEL32.42)
|
|
* A thunkbuffer link routine
|
|
* The thunkbuf looks like:
|
|
*
|
|
* 00: DWORD length ? don't know exactly
|
|
* 04: SEGPTR ptr ? where does it point to?
|
|
* The pointer ptr is written into the first DWORD of 'thunk'.
|
|
* (probably correct implemented)
|
|
*/
|
|
BOOL32
|
|
_KERNEL32_43(LPDWORD thunk,LPCSTR thkbuf,DWORD len,LPCSTR dll16,LPCSTR dll32) {
|
|
HINSTANCE16 hmod;
|
|
LPDWORD addr;
|
|
SEGPTR segaddr;
|
|
|
|
fprintf(stderr,"_KERNEL32_43(%p,%s,0x%08lx,%s,%s)\n",thunk,thkbuf,len,dll16,dll32);
|
|
|
|
hmod = LoadLibrary16(dll16);
|
|
if (hmod<32) {
|
|
fprintf(stderr,"->failed to load 16bit DLL %s, error %d\n",dll16,hmod);
|
|
return NULL;
|
|
}
|
|
segaddr = (DWORD)WIN32_GetProcAddress16(hmod,(LPSTR)thkbuf);
|
|
if (!segaddr) {
|
|
fprintf(stderr,"->no %s exported from %s!\n",thkbuf,dll16);
|
|
return NULL;
|
|
}
|
|
addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
|
|
if (addr[0] != len) {
|
|
fprintf(stderr,"->thkbuf length mismatch? %ld vs %ld\n",len,addr[0]);
|
|
return NULL;
|
|
}
|
|
if (!addr[1])
|
|
return 0;
|
|
*(DWORD*)thunk = addr[1];
|
|
return addr[1];
|
|
}
|
|
|
|
/***********************************************************************
|
|
* _KERNEL32_45 (KERNEL32.44)
|
|
* FIXME: not sure what it does
|
|
*/
|
|
VOID
|
|
_KERNEL32_45(DWORD x,CONTEXT *context) {
|
|
fprintf(stderr,"_KERNEL32_45(0x%08lx,%%eax=0x%08lx,%%cx=0x%04lx,%%edx=0x%08lx)\n",
|
|
x,(DWORD)EAX_reg(context),(DWORD)CX_reg(context),(DWORD)EDX_reg(context)
|
|
);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* (KERNEL32.40)
|
|
* A thunk setup routine.
|
|
* Expects a pointer to a preinitialized thunkbuffer in the first argument
|
|
* looking like:
|
|
* 00..03: unknown (some pointer to the 16bit struct?)
|
|
* 04: EB1E jmp +0x20
|
|
*
|
|
* 06..23: unknown (space for replacement code, check .90)
|
|
*
|
|
* 24:>E8xxxxxxxx call <32bitoffset xxxxxxxx>
|
|
* 29: 58 pop eax
|
|
* 2A: 2D2500xxxx and eax,0x2500xxxx
|
|
* 2F: BAxxxxxxxx mov edx,xxxxxxxx
|
|
* 34: 68yyyyyyyy push KERNEL32.90
|
|
* 39: C3 ret
|
|
*
|
|
* 3A: EB1E jmp +0x20
|
|
* 3E ... 59: unknown (space for replacement code?)
|
|
* 5A: E8xxxxxxxx call <32bitoffset xxxxxxxx>
|
|
* 5F: 5A pop edx
|
|
* 60: 81EA25xxxxxx sub edx, 0x25xxxxxx
|
|
* 66: 52 push edx
|
|
* 67: 68xxxxxxxx push xxxxxxxx
|
|
* 6C: 68yyyyyyyy push KERNEL32.89
|
|
* 71: C3 ret
|
|
* 72: end?
|
|
* This function checks if the code is there, and replaces the yyyyyyyy entries
|
|
* by the functionpointers.
|
|
* The thunkbuf looks like:
|
|
*
|
|
* 00: DWORD length ? don't know exactly
|
|
* 04: SEGPTR ptr ? where does it point to?
|
|
* The segpointer ptr is written into the first DWORD of 'thunk'.
|
|
* (probably correct implemented)
|
|
*/
|
|
|
|
LPVOID
|
|
_KERNEL32_41(LPBYTE thunk,LPCSTR thkbuf,DWORD len,LPCSTR dll16,LPCSTR dll32) {
|
|
HMODULE32 hkrnl32 = WIN32_GetModuleHandleA("KERNEL32");
|
|
HMODULE16 hmod;
|
|
LPDWORD addr,addr2;
|
|
DWORD segaddr;
|
|
|
|
fprintf(stderr,"KERNEL32_41(%p,%s,%ld,%s,%s)\n",
|
|
thunk,thkbuf,len,dll16,dll32
|
|
);
|
|
|
|
/* FIXME: add checks for valid code ... */
|
|
/* write pointers to kernel32.89 and kernel32.90 (+ordinal base of 1) */
|
|
*(DWORD*)(thunk+0x35) = (DWORD)GetProcAddress32(hkrnl32,(LPSTR)91);
|
|
*(DWORD*)(thunk+0x6D) = (DWORD)GetProcAddress32(hkrnl32,(LPSTR)90);
|
|
|
|
|
|
hmod = LoadLibrary16(dll16);
|
|
if (hmod<32) {
|
|
fprintf(stderr,"->failed to load 16bit DLL %s, error %d\n",dll16,hmod);
|
|
return NULL;
|
|
}
|
|
segaddr = (DWORD)WIN32_GetProcAddress16(hmod,(LPSTR)thkbuf);
|
|
if (!segaddr) {
|
|
fprintf(stderr,"->no %s exported from %s!\n",thkbuf,dll16);
|
|
return NULL;
|
|
}
|
|
addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
|
|
if (addr[0] != len) {
|
|
fprintf(stderr,"->thkbuf length mismatch? %ld vs %ld\n",len,addr[0]);
|
|
return NULL;
|
|
}
|
|
addr2 = PTR_SEG_TO_LIN(addr[1]);
|
|
if (HIWORD(addr2))
|
|
*(DWORD*)thunk = (DWORD)addr2;
|
|
return addr2;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* (KERNEL32.33)
|
|
* Returns some internal value.... probably the default environment database?
|
|
*/
|
|
DWORD
|
|
_KERNEL32_34() {
|
|
fprintf(stderr,"KERNEL32_34(), STUB returning 0\n");
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* (KERNEL32.90)
|
|
* Thunk priming? function
|
|
* Rewrites the first part of the thunk to use the QT_Thunk interface.
|
|
* Replaces offset 4 ... 24 by:
|
|
*
|
|
* 33C9 xor ecx, ecx
|
|
* 8A4DFC mov cl , [ebp-04]
|
|
* 8B148Dxxxxxxxx mov edx, [4*ecx + (EAX+EDX)]
|
|
* B8yyyyyyyy mov eax, QT_Thunk
|
|
* FFE0 jmp eax
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* CC int 03
|
|
* and jumps to the start of that code.
|
|
* (ok)
|
|
*/
|
|
VOID
|
|
_KERNEL32_91(CONTEXT *context) {
|
|
LPBYTE x;
|
|
|
|
fprintf(stderr,"_KERNEL32_91(eax=0x%08lx,edx=0x%08lx)\n",
|
|
EAX_reg(context),EDX_reg(context)
|
|
);
|
|
x = (LPBYTE)EAX_reg(context);
|
|
*x++ = 0x33;*x++=0xC9; /* xor ecx,ecx */
|
|
*x++ = 0x8A;*x++=0x4D;*x++=0xFC; /* mov cl,[ebp-04] */
|
|
*x++ = 0x8B;*x++=0x14;*x++=0x8D;*(DWORD*)x= EAX_reg(context)+EDX_reg(context);
|
|
x+=4; /* mov edx, [4*ecx + (EAX+EDX) */
|
|
*x++ = 0xB8; *(DWORD*)x = (DWORD)GetProcAddress32(WIN32_GetModuleHandleA("KERNEL32"),"QT_Thunk");
|
|
x+=4; /* mov eax , QT_Thunk */
|
|
*x++ = 0xFF; *x++ = 0xE0; /* jmp eax */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
*x++ = 0xCC; /* int 03 */
|
|
EIP_reg(context) = EAX_reg(context);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* (KERNEL32.45)
|
|
* Another thunkbuf link routine.
|
|
* The start of the thunkbuf looks like this:
|
|
* 00: DWORD length
|
|
* 04: SEGPTR address for thunkbuffer pointer
|
|
*/
|
|
VOID
|
|
_KERNEL32_46(LPBYTE thunk,LPSTR thkbuf,DWORD len,LPSTR dll16,LPSTR dll32) {
|
|
LPDWORD addr;
|
|
HMODULE16 hmod;
|
|
SEGPTR segaddr;
|
|
|
|
fprintf(stderr,"KERNEL32_46(%p,%s,%lx,%s,%s)\n",
|
|
thunk,thkbuf,len,dll16,dll32
|
|
);
|
|
hmod = LoadLibrary16(dll16);
|
|
if (hmod < 32) {
|
|
fprintf(stderr,"->couldn't load %s, error %d\n",dll16,hmod);
|
|
return;
|
|
}
|
|
segaddr = (SEGPTR)WIN32_GetProcAddress16(hmod,thkbuf);
|
|
if (!segaddr) {
|
|
fprintf(stderr,"-> haven't found %s in %s!\n",thkbuf,dll16);
|
|
return;
|
|
}
|
|
addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
|
|
if (addr[0] != len) {
|
|
fprintf(stderr,"-> length of thkbuf differs from expected length! (%ld vs %ld)\n",addr[0],len);
|
|
return;
|
|
}
|
|
*(DWORD*)PTR_SEG_TO_LIN(addr[1]) = (DWORD)thunk;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* _KERNEL32_87
|
|
* Check if thunking is initialized (ss selector set up etc.)
|
|
*/
|
|
BOOL32 _KERNEL32_87() {
|
|
fprintf(stderr,"KERNEL32_87 stub, returning TRUE\n");
|
|
return TRUE;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* _KERNEL32_88
|
|
* One of the real thunking functions
|
|
* Probably implemented totally wrong.
|
|
*/
|
|
BOOL32 _KERNEL32_88(DWORD nr,DWORD flags,LPVOID fun,DWORD *hmm) {
|
|
fprintf(stderr,"KERNEL32_88(%ld,0x%08lx,%p,%p) stub, returning TRUE\n",
|
|
nr,flags,fun,hmm
|
|
);
|
|
#ifndef WINELIB
|
|
switch (nr) {
|
|
case 0: CallTo32_0(fun);
|
|
break;
|
|
case 4: CallTo32_1(fun,hmm[0]);
|
|
break;
|
|
case 8: CallTo32_2(fun,hmm[0],hmm[1]);
|
|
break;
|
|
default:
|
|
fprintf(stderr," unsupported nr of arguments, %ld\n",nr);
|
|
break;
|
|
|
|
}
|
|
#endif
|
|
return TRUE;
|
|
}
|