/* * Win32 ordinal only exported functions * * Copyright 1997 Marcus Meissner */ #include #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; }