Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

410 lines
11 KiB

  1. //************************************************************************
  2. //
  3. // dpmfntd.c : Dynamic Patch Module for NTDLL API family
  4. //
  5. // History:
  6. // 26-jan-02 cmjones created it.
  7. //
  8. //************************************************************************
  9. #ifdef DBG
  10. unsigned long dwLogLevel = 0;
  11. #endif
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include "dpmtbls.h"
  17. #include "dpmdbg.h" // include handy debug print macros
  18. #include "shimdb.h"
  19. BOOL DllInitProc(HMODULE hModule, DWORD Reason, PCONTEXT pContext);
  20. PFAMILY_TABLE DpmInitFamTable(PFAMILY_TABLE,
  21. HMODULE,
  22. PVOID,
  23. PVOID,
  24. LPWSTR,
  25. PDPMMODULESETS);
  26. void DpmDestroyFamTable(PFAMILY_TABLE pgDpmFamTbl, PFAMILY_TABLE pFT);
  27. #define GROW_HEAP_AS_NEEDED 0
  28. HANDLE hHeap = NULL;
  29. DWORD dwTlsIndex;
  30. char szShimEngDll[] = "\\ShimEng.dll";
  31. BOOL DllInitProc(HMODULE hModule, DWORD Reason, PCONTEXT pContext)
  32. {
  33. BOOL bRet = TRUE;
  34. UNREFERENCED_PARAMETER(hModule);
  35. UNREFERENCED_PARAMETER(pContext);
  36. switch(Reason) {
  37. case DLL_PROCESS_ATTACH:
  38. if((hHeap = HeapCreate(0, 4096, GROW_HEAP_AS_NEEDED)) == NULL) {
  39. DPMDBGPRN("NTVDM::DpmfNtd:Can't initialize heap!\n");
  40. bRet = FALSE;
  41. }
  42. dwTlsIndex = TlsAlloc();
  43. if(dwTlsIndex == TLS_OUT_OF_INDEXES) {
  44. DPMDBGPRN("NTVDM::DpmfNtd:Can't initialize TLS!\n");
  45. bRet = FALSE;
  46. }
  47. break;
  48. case DLL_PROCESS_DETACH:
  49. if(hHeap) {
  50. HeapDestroy(hHeap);
  51. }
  52. TlsFree(dwTlsIndex);
  53. break;
  54. }
  55. return bRet;
  56. }
  57. PFAMILY_TABLE DpmInitFamTable(PFAMILY_TABLE pgDpmFamTbl,
  58. HMODULE hMod,
  59. PVOID hSdb,
  60. PVOID pSdbQuery,
  61. LPWSTR pwszAppFilePath,
  62. PDPMMODULESETS pModSet)
  63. {
  64. int i, numApis, len;
  65. PVOID lpdpmfn;
  66. PFAMILY_TABLE pFT = NULL;
  67. PVOID *pFN = NULL;
  68. PVOID *pShimTbl = NULL;
  69. PAPIDESC pApiDesc = NULL;
  70. VDMTABLE VdmTbl;
  71. char szShimEng[MAX_PATH];
  72. HMODULE hModShimEng = NULL;
  73. LPFNSE_SHIMNTVDM lpShimNtvdm;
  74. DPMDBGPRN("NTVDM::DpmfNtd:Initialziing File I/O API tables\n");
  75. // Get hooked API count from global table
  76. numApis = pgDpmFamTbl->numHookedAPIs;
  77. // Allocate a new family table
  78. pFT = (PFAMILY_TABLE)HeapAlloc(hHeap,
  79. HEAP_ZERO_MEMORY,
  80. sizeof(FAMILY_TABLE));
  81. if(!pFT) {
  82. DPMDBGPRN("NTVDM::DpmfNtd:DpmInit:malloc 1 failed\n");
  83. goto ErrorExit;
  84. }
  85. // Allocate the shim dispatch table for this family in this task
  86. pShimTbl = (PVOID *)HeapAlloc(hHeap,
  87. HEAP_ZERO_MEMORY,
  88. numApis * sizeof(PVOID));
  89. if(!pShimTbl) {
  90. DPMDBGPRN("NTVDM::DpmfNtd:DpmInit:malloc 2 failed\n");
  91. goto ErrorExit;
  92. }
  93. pFT->pDpmShmTbls = pShimTbl;
  94. // Allocate an array of ptrs to hooked API's
  95. pFN = (PVOID *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, numApis * sizeof(PVOID));
  96. if(!pFN) {
  97. DPMDBGPRN("NTVDM::DpmfNtd:DpmInit:malloc 3 failed\n");
  98. goto ErrorExit;
  99. }
  100. pFT->pfn = pFN;
  101. pFT->numHookedAPIs = numApis;
  102. pFT->hMod = hMod;
  103. // Allocate a temp array of APIDESC structs to help attach shims
  104. pApiDesc = (PAPIDESC)HeapAlloc(hHeap,
  105. HEAP_ZERO_MEMORY,
  106. numApis * sizeof(APIDESC));
  107. if(!pApiDesc) {
  108. DPMDBGPRN("NTVDM::DpmfNtd:DpmInit:malloc 4 failed\n");
  109. goto ErrorExit;
  110. }
  111. VdmTbl.nApiCount = numApis;
  112. VdmTbl.ppfnOrig = pShimTbl;
  113. VdmTbl.pApiDesc = pApiDesc;
  114. // Fill in the family table with ptrs to the patch functions in this DLL.
  115. for(i = 0; i < numApis; i++) {
  116. // must start with 1 since EXPORT ordinals can't be == 0
  117. lpdpmfn = (PVOID)GetProcAddress(hMod, (LPCSTR)MAKELONG(i+1, 0));
  118. if(!lpdpmfn) {
  119. DPMDBGPRN("NTVDM::DpmfNtd:DpmInit:Unable to get proc address\n");
  120. goto ErrorExit;
  121. }
  122. // save ptr to the real API in the shim table until it gets shimmed
  123. pShimTbl[i] = pgDpmFamTbl->pfn[i];
  124. // relate the corresponding module and API name to the API function ptr
  125. pApiDesc[i].pszModule = (char *)pModSet->ApiModuleName;
  126. pApiDesc[i].pszApi = (char *)pModSet->ApiNames[i];
  127. // save ptr to the patch function
  128. pFN[i] = lpdpmfn;
  129. }
  130. // Only do this if we need to attach the shim engine.
  131. GetSystemDirectory(szShimEng, MAX_PATH);
  132. strcat(szShimEng, szShimEngDll);
  133. hModShimEng = LoadLibrary(szShimEng);
  134. pFT->hModShimEng = hModShimEng;
  135. if(NULL == hModShimEng) {
  136. DPMDBGPRN("NTVDM::dpmfntd:DpmInit:ShimEng load failed\n");
  137. goto ErrorExit;
  138. }
  139. lpShimNtvdm = (LPFNSE_SHIMNTVDM)GetProcAddress(hModShimEng, "SE_ShimNTVDM");
  140. if(!lpShimNtvdm) {
  141. DPMDBGPRN("NTVDM::DpmfNtd:DpmInit:GetProcAddress failed\n");
  142. goto ErrorExit;
  143. }
  144. // Patch the shim dispatch table with the shim function ptrs
  145. // If this fails we will stick with ptrs to the original API's
  146. (lpShimNtvdm)(pwszAppFilePath, hSdb, pSdbQuery, &VdmTbl);
  147. // Do this if you want dispatch directly to the shim functions
  148. // for(i = 0; i < numApis; i++) {
  149. // pFN[i] = pShimTbl[i];
  150. // }
  151. // HeapFree(hHeap, 0, pShimTbl);
  152. // pFT->pDpmShmTbls = NULL;
  153. if(!TlsSetValue(dwTlsIndex, pFT)) {
  154. DPMDBGPRN("NTVDM::DpmfNtd:DpmInit:TLS set failed\n");
  155. goto ErrorExit;
  156. }
  157. if(pApiDesc) {
  158. HeapFree(hHeap, 0, pApiDesc);
  159. }
  160. DPMDBGPRN1(" DpmfNtd:Returning File I/o API tables: %#lx\n",pFT);
  161. return(pFT);
  162. ErrorExit:
  163. DPMDBGPRN(" DpmfNtd:Init failed: Returning NULL\n");
  164. DpmDestroyFamTable(pgDpmFamTbl, pFT);
  165. if(pApiDesc) {
  166. HeapFree(hHeap, 0, pApiDesc);
  167. }
  168. return(NULL);
  169. }
  170. void DpmDestroyFamTable(PFAMILY_TABLE pgDpmFamTbl, PFAMILY_TABLE pFT)
  171. {
  172. PVDM_TIB pVdmTib;
  173. PVOID *pShimTbl;
  174. LPFNSE_REMOVENTVDM lpfnSE_RemoveNtvdmTask = NULL;
  175. DPMDBGPRN("NTVDM::DpmfNtd:Destroying NTDLL API tables for task\n");
  176. // if this task is using the global table for this family, nothing to do
  177. if(!pFT || pFT == pgDpmFamTbl)
  178. return;
  179. pShimTbl = pFT->pDpmShmTbls;
  180. if(pShimTbl) {
  181. HeapFree(hHeap, 0, pShimTbl);
  182. }
  183. if(pFT->pfn) {
  184. HeapFree(hHeap, 0, pFT->pfn);
  185. }
  186. // See if the shim engine is attached & detach it
  187. if(pFT->hModShimEng) {
  188. lpfnSE_RemoveNtvdmTask =
  189. (LPFNSE_REMOVENTVDM)GetProcAddress(pFT->hModShimEng,
  190. "SE_RemoveNTVDMTask");
  191. if(lpfnSE_RemoveNtvdmTask) {
  192. (lpfnSE_RemoveNtvdmTask)(NtCurrentTeb()->ClientId.UniqueThread);
  193. }
  194. FreeLibrary(pFT->hModShimEng);
  195. }
  196. HeapFree(hHeap, 0, pFT);
  197. }
  198. // ^^^^^^^^^^ All the above should be in every DPM module. ^^^^^^^^^^^^
  199. // vvvvvvvvvv Define module specific stuff below. vvvvvvvvvvvv
  200. DWORD dpmNtOpenFile(PHANDLE FileHandle,
  201. ACCESS_MASK DesiredAccess,
  202. POBJECT_ATTRIBUTES ObjectAttributes,
  203. PIO_STATUS_BLOCK IoStatusBlock,
  204. ULONG ShareAccess,
  205. ULONG OpenOptions)
  206. {
  207. PFAMILY_TABLE pFT = (PFAMILY_TABLE)TlsGetValue(dwTlsIndex);
  208. DWORD ret = 0;
  209. DPMDBGPRN("NtOpenFile: ");
  210. ret = SHM_NtOpenFile(FileHandle,
  211. DesiredAccess,
  212. ObjectAttributes,
  213. IoStatusBlock,
  214. ShareAccess,
  215. OpenOptions);
  216. DPMDBGPRN1(" -> %#lx\n", ret);
  217. return(ret);
  218. }
  219. DWORD dpmNtQueryDirectoryFile(HANDLE FileHandle,
  220. HANDLE Event OPTIONAL,
  221. PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  222. PVOID ApcContext OPTIONAL,
  223. PIO_STATUS_BLOCK IoStatusBlock,
  224. PVOID FileInformation,
  225. ULONG Length,
  226. FILE_INFORMATION_CLASS FileInformationClass,
  227. BOOLEAN ReturnSingleEntry,
  228. PUNICODE_STRING FileName OPTIONAL,
  229. BOOLEAN RestartScan)
  230. {
  231. PFAMILY_TABLE pFT = (PFAMILY_TABLE)TlsGetValue(dwTlsIndex);
  232. DWORD ret = 0;
  233. DPMDBGPRN("NtQueryDirectoryFile: ");
  234. ret = SHM_NtQueryDirectoryFile(FileHandle,
  235. Event,
  236. ApcRoutine,
  237. ApcContext,
  238. IoStatusBlock,
  239. FileInformation,
  240. Length,
  241. FileInformationClass,
  242. ReturnSingleEntry,
  243. FileName,
  244. RestartScan);
  245. DPMDBGPRN1(" -> %#lx\n", ret);
  246. return(ret);
  247. }
  248. DWORD dpmRtlGetFullPathName_U(PCWSTR lpFileName,
  249. ULONG nBufferLength,
  250. PWSTR lpBuffer,
  251. PWSTR *lpFilePart)
  252. {
  253. PFAMILY_TABLE pFT = (PFAMILY_TABLE)TlsGetValue(dwTlsIndex);
  254. DWORD ret = 0;
  255. DPMDBGPRN("RtlGetFullPathName_U: ");
  256. ret = SHM_RtlGetFullPathName_U(lpFileName,
  257. nBufferLength,
  258. lpBuffer,
  259. lpFilePart);
  260. DPMDBGPRN1(" -> %#lx\n", ret);
  261. return(ret);
  262. }
  263. DWORD dpmRtlGetCurrentDirectory_U(ULONG nBufferLength, PWSTR lpBuffer)
  264. {
  265. PFAMILY_TABLE pFT = (PFAMILY_TABLE)TlsGetValue(dwTlsIndex);
  266. DWORD ret = 0;
  267. DPMDBGPRN("RtlGetCurrentDirectory_U: ");
  268. ret = SHM_RtlGetCurrentDirectory_U(nBufferLength, lpBuffer);
  269. DPMDBGPRN1(" -> %#lx\n", ret);
  270. return(ret);
  271. }
  272. NTSTATUS dpmRtlSetCurrentDirectory_U(PUNICODE_STRING PathName)
  273. {
  274. PFAMILY_TABLE pFT = (PFAMILY_TABLE)TlsGetValue(dwTlsIndex);
  275. NTSTATUS ret = 0;
  276. DPMDBGPRN("RtlSetCurrentDirectory_U: ");
  277. ret = SHM_RtlSetCurrentDirectory_U(PathName);
  278. DPMDBGPRN1(" -> %#lx\n", ret);
  279. return(ret);
  280. }
  281. DWORD dpmNtVdmControl(VDMSERVICECLASS vdmClass, PVOID pInfo)
  282. {
  283. PFAMILY_TABLE pFT = (PFAMILY_TABLE)TlsGetValue(dwTlsIndex);
  284. NTSTATUS ret = 0;
  285. DPMDBGPRN("NtVdmControl: ");
  286. ret = SHM_NtVdmControl(vdmClass, pInfo);
  287. DPMDBGPRN1(" -> %#lx\n", ret);
  288. return(ret);
  289. }