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.

531 lines
14 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. Money2002.cpp
  5. Abstract:
  6. Retry passwords at 128-bit encryption if 40-bit fails. Most code from Money
  7. team.
  8. We have to patch the API directly since it is called from within it's own
  9. DLL, i.e. it doesn't go through the import table.
  10. The function we're patching is cdecl and is referenced by it's ordinal
  11. because the name is mangled.
  12. Notes:
  13. This is an app specific shim.
  14. History:
  15. 07/11/2002 linstev Created
  16. --*/
  17. #include "precomp.h"
  18. IMPLEMENT_SHIM_BEGIN(Money2002)
  19. #include "ShimHookMacro.h"
  20. #include <wincrypt.h>
  21. APIHOOK_ENUM_BEGIN
  22. APIHOOK_ENUM_ENTRY(LoadLibraryA)
  23. APIHOOK_ENUM_ENTRY(FreeLibrary)
  24. APIHOOK_ENUM_END
  25. #define Assert(a)
  26. void *crtmalloc(size_t size)
  27. {
  28. HMODULE hMod = GetModuleHandleW(L"msvcrt.dll");
  29. if (hMod) {
  30. typedef void * (__cdecl *_pfn_malloc)(size_t size);
  31. _pfn_malloc pfnmalloc = (_pfn_malloc) GetProcAddress(hMod, "malloc");
  32. if (pfnmalloc) {
  33. return pfnmalloc(size);
  34. }
  35. }
  36. return malloc(size);
  37. }
  38. void crtfree(void *memblock)
  39. {
  40. HMODULE hMod = GetModuleHandleW(L"msvcrt.dll");
  41. if (hMod) {
  42. _pfn_free pfnfree = (_pfn_free) GetProcAddress(hMod, "free");
  43. if (pfnfree) {
  44. pfnfree(memblock);
  45. return;
  46. }
  47. }
  48. free(memblock);
  49. }
  50. //
  51. // This section from the Money team
  52. //
  53. #define MAXLEN (100)
  54. #define ENCRYPT_BLOCK_SIZE (8)
  55. #define ENCRYPT_ALGORITHM CALG_RC2
  56. #define KEY_LENGTH (128)
  57. #define KEY_LENGTH40 (40)
  58. #define LgidMain(lcid) PRIMARYLANGID(LANGIDFROMLCID(lcid))
  59. #define LgidSub(lcid) SUBLANGID(LANGIDFROMLCID(lcid))
  60. // this function is only used for conversion
  61. BOOL FFrenchLCID()
  62. {
  63. LCID lcidSys=::GetSystemDefaultLCID();
  64. if (LgidMain(lcidSys)==LANG_FRENCH && LgidSub(lcidSys)==SUBLANG_FRENCH)
  65. return TRUE;
  66. else
  67. return FALSE;
  68. }
  69. // the smallest buffer size is 8
  70. #define BLOCKSIZE 8
  71. // process a block, either encrypt it or decrypt it
  72. // this function is only used for conversion
  73. void ProcessBlock(BOOL fEncrypt, BYTE * buffer)
  74. {
  75. BYTE mask[BLOCKSIZE]; // mask array
  76. BYTE temp[BLOCKSIZE]; // temporary array
  77. int rgnScramble[BLOCKSIZE]; // scramble array
  78. int i;
  79. // initialized scramble array
  80. for (i=0; i<BLOCKSIZE; i++)
  81. rgnScramble[i] = i;
  82. // generate mask and scramble indice
  83. for (i=0; i<BLOCKSIZE; i++)
  84. mask[i] = (BYTE)rand();
  85. for (i=0; i<4*BLOCKSIZE; i++)
  86. {
  87. int temp;
  88. int ind = rand() % BLOCKSIZE;
  89. temp = rgnScramble[i%BLOCKSIZE];
  90. rgnScramble[i%BLOCKSIZE] = rgnScramble[ind];
  91. rgnScramble[ind] = temp;
  92. }
  93. if (fEncrypt)
  94. {
  95. // xor encryption
  96. for (i=0; i<BLOCKSIZE; i++)
  97. mask[i] ^= buffer[i];
  98. // scramble the data
  99. for (i=0; i<BLOCKSIZE; i++)
  100. buffer[rgnScramble[i]] = mask[i];
  101. }
  102. else
  103. {
  104. // descramble the data
  105. for (i=0; i<BLOCKSIZE; i++)
  106. temp[i] = buffer[rgnScramble[i]];
  107. // xor decryption
  108. for (i=0; i<BLOCKSIZE; i++)
  109. buffer[i] = (BYTE) (temp[i] ^ mask[i]);
  110. }
  111. }
  112. // this function is only used for conversion
  113. BYTE * DecryptFrench(const BYTE * pbEncryptedBlob, DWORD cbEncryptedBlob, DWORD * pcbDecryptedBlob, LPCSTR szPassword)
  114. {
  115. BYTE buffer[BLOCKSIZE];
  116. int i;
  117. unsigned int seed = 0;
  118. unsigned int seedAdd = 0;
  119. BYTE * pb;
  120. BYTE * pbResult = NULL;
  121. unsigned int cBlocks;
  122. unsigned int cbResult = 0;
  123. unsigned int iBlocks;
  124. // make sure blob is at least 1 block long
  125. // and it's an integral number of blocks
  126. Assert(cbEncryptedBlob >= BLOCKSIZE);
  127. Assert(cbEncryptedBlob % BLOCKSIZE == 0);
  128. *pcbDecryptedBlob = 0;
  129. if (cbEncryptedBlob < BLOCKSIZE || cbEncryptedBlob % BLOCKSIZE != 0)
  130. return NULL;
  131. // calculate initial seed
  132. while (*szPassword)
  133. seed += *szPassword++;
  134. srand(seed);
  135. // retrieve the first block
  136. for (i=0; i<BLOCKSIZE; i++)
  137. buffer[i] = *pbEncryptedBlob++;
  138. ProcessBlock(FALSE, buffer);
  139. // find out the byte count and addon seed
  140. cbResult = *pcbDecryptedBlob = *((DWORD*)buffer);
  141. seedAdd = *(((DWORD*)buffer) + 1);
  142. // find out how many blocks we need
  143. cBlocks = 1 + (*pcbDecryptedBlob-1)/BLOCKSIZE;
  144. // make sure we have the right number of blocks
  145. Assert(cBlocks + 1 == cbEncryptedBlob / BLOCKSIZE);
  146. if (cBlocks + 1 == cbEncryptedBlob / BLOCKSIZE)
  147. {
  148. // allocate output memory
  149. pbResult = (BYTE*)crtmalloc(*pcbDecryptedBlob);
  150. if (pbResult)
  151. {
  152. // re-seed
  153. srand(seed + seedAdd);
  154. pb = pbResult;
  155. // process all blocks of data
  156. for (iBlocks=0; iBlocks<cBlocks; iBlocks++)
  157. {
  158. for (i=0; i<BLOCKSIZE; i++)
  159. buffer[i] = *pbEncryptedBlob++;
  160. ProcessBlock(FALSE, buffer);
  161. for (i=0; i<BLOCKSIZE && cbResult>0; i++, cbResult--)
  162. *pb++ = buffer[i];
  163. }
  164. }
  165. }
  166. if (!pbResult)
  167. *pcbDecryptedBlob = 0;
  168. return pbResult;
  169. }
  170. HCRYPTKEY CreateSessionKey(HCRYPTPROV hCryptProv, LPCSTR szPassword, BOOL fConvert, BOOL f40bit)
  171. {
  172. HCRYPTHASH hHash = 0;
  173. HCRYPTKEY hKey = 0;
  174. DWORD dwEffectiveKeyLen;
  175. DWORD dwPadding = PKCS5_PADDING;
  176. DWORD dwMode = CRYPT_MODE_CBC;
  177. if (f40bit)
  178. dwEffectiveKeyLen=KEY_LENGTH40;
  179. else
  180. dwEffectiveKeyLen= KEY_LENGTH;
  181. //--------------------------------------------------------------------
  182. // The file will be encrypted with a session key derived from a
  183. // password.
  184. // The session key will be recreated when the file is decrypted.
  185. //--------------------------------------------------------------------
  186. // Create a hash object.
  187. if (!CryptCreateHash(
  188. hCryptProv,
  189. CALG_MD5,
  190. 0,
  191. 0,
  192. &hHash))
  193. {
  194. goto CLEANUP;
  195. }
  196. //--------------------------------------------------------------------
  197. // Hash the password.
  198. if (!CryptHashData(
  199. hHash,
  200. (BYTE *)szPassword,
  201. strlen(szPassword)*sizeof(CHAR),
  202. 0))
  203. {
  204. goto CLEANUP;
  205. }
  206. //--------------------------------------------------------------------
  207. // Derive a session key from the hash object.
  208. if (!CryptDeriveKey(
  209. hCryptProv,
  210. ENCRYPT_ALGORITHM,
  211. hHash,
  212. (fConvert ? 0 : (KEY_LENGTH << 16) | CRYPT_EXPORTABLE),
  213. &hKey))
  214. {
  215. goto CLEANUP;
  216. }
  217. // set effective key length explicitly
  218. if (!CryptSetKeyParam(
  219. hKey,
  220. KP_EFFECTIVE_KEYLEN,
  221. (BYTE*)&dwEffectiveKeyLen,
  222. 0))
  223. {
  224. if(hKey)
  225. CryptDestroyKey(hKey);
  226. hKey = 0;
  227. goto CLEANUP;
  228. }
  229. if (!fConvert && !f40bit)
  230. {
  231. // set padding explicitly
  232. if (!CryptSetKeyParam(
  233. hKey,
  234. KP_PADDING,
  235. (BYTE*)&dwPadding,
  236. 0))
  237. {
  238. if(hKey)
  239. CryptDestroyKey(hKey);
  240. hKey = 0;
  241. goto CLEANUP;
  242. }
  243. // set mode explicitly
  244. if (!CryptSetKeyParam(
  245. hKey,
  246. KP_MODE,
  247. (BYTE*)&dwMode,
  248. 0))
  249. {
  250. if(hKey)
  251. CryptDestroyKey(hKey);
  252. hKey = 0;
  253. goto CLEANUP;
  254. }
  255. }
  256. //--------------------------------------------------------------------
  257. // Destroy the hash object.
  258. CLEANUP:
  259. if (hHash)
  260. CryptDestroyHash(hHash);
  261. return hKey;
  262. }
  263. BYTE * DecryptWorker(const BYTE * pbEncryptedBlob, DWORD cbEncryptedBlob, DWORD * pcbDecryptedBlob, LPCSTR szPassword, BOOL fConvert, BOOL f40bit, BOOL* pfRet)
  264. {
  265. HCRYPTPROV hCryptProv = NULL; // CSP handle
  266. HCRYPTKEY hKey = 0;
  267. DWORD cbDecryptedMessage = 0;
  268. BYTE* pbDecryptedMessage = NULL;
  269. DWORD dwBlockLen;
  270. DWORD dwBufferLen;
  271. Assert(pfRet);
  272. *pfRet=TRUE;
  273. //--------------------------------------------------------------------
  274. // Begin processing.
  275. Assert(pcbDecryptedBlob);
  276. *pcbDecryptedBlob = 0;
  277. if (!pbEncryptedBlob || cbEncryptedBlob == 0)
  278. return NULL;
  279. if (FFrenchLCID() && fConvert)
  280. return DecryptFrench(pbEncryptedBlob, cbEncryptedBlob, pcbDecryptedBlob, szPassword);
  281. //--------------------------------------------------------------------
  282. // Get a handle to a cryptographic provider.
  283. if (!CryptAcquireContext(
  284. &hCryptProv, // Address for handle to be returned.
  285. NULL, // Container
  286. (fConvert ? NULL : MS_ENHANCED_PROV), // Use the default provider.
  287. PROV_RSA_FULL, // Need to both encrypt and sign.
  288. CRYPT_VERIFYCONTEXT)) // flags.
  289. {
  290. Assert(FALSE);
  291. goto CLEANUP;
  292. }
  293. //--------------------------------------------------------------------
  294. // Create the session key.
  295. hKey = CreateSessionKey(hCryptProv, szPassword, fConvert, f40bit);
  296. if (!hKey)
  297. {
  298. goto CLEANUP;
  299. }
  300. dwBlockLen = cbEncryptedBlob;
  301. dwBufferLen = dwBlockLen;
  302. //--------------------------------------------------------------------
  303. // Allocate memory.
  304. pbDecryptedMessage = (BYTE *)crtmalloc(dwBufferLen);
  305. if (!pbDecryptedMessage)
  306. {
  307. // Out of memory
  308. goto CLEANUP;
  309. }
  310. memcpy(pbDecryptedMessage, pbEncryptedBlob, cbEncryptedBlob);
  311. cbDecryptedMessage = cbEncryptedBlob;
  312. //--------------------------------------------------------------------
  313. // Decrypt data.
  314. if (!CryptDecrypt(
  315. hKey,
  316. 0,
  317. TRUE,
  318. 0,
  319. pbDecryptedMessage,
  320. &cbDecryptedMessage))
  321. {
  322. crtfree(pbDecryptedMessage);
  323. pbDecryptedMessage = NULL;
  324. cbDecryptedMessage = 0;
  325. *pfRet=FALSE;
  326. goto CLEANUP;
  327. }
  328. //--------------------------------------------------------------------
  329. // Clean up memory.
  330. CLEANUP:
  331. if(hKey)
  332. CryptDestroyKey(hKey);
  333. if (hCryptProv)
  334. {
  335. CryptReleaseContext(hCryptProv,0);
  336. // The CSP has been released.
  337. }
  338. *pcbDecryptedBlob = cbDecryptedMessage;
  339. return pbDecryptedMessage;
  340. }
  341. BYTE * __cdecl Decrypt(const BYTE * pbEncryptedBlob, DWORD cbEncryptedBlob, DWORD * pcbDecryptedBlob, LPCSTR szEncryptionPassword, BOOL fConvert)
  342. {
  343. BYTE* pbDecryptedMessage;
  344. BOOL fRet;
  345. // try 128 bit first, if we fail, try 40 bit again.
  346. pbDecryptedMessage = DecryptWorker(pbEncryptedBlob, cbEncryptedBlob, pcbDecryptedBlob, szEncryptionPassword, fConvert, FALSE, &fRet);
  347. if (!fRet)
  348. {
  349. if (pbDecryptedMessage)
  350. crtfree(pbDecryptedMessage);
  351. pbDecryptedMessage = DecryptWorker(pbEncryptedBlob, cbEncryptedBlob, pcbDecryptedBlob, szEncryptionPassword, fConvert, TRUE, &fRet);
  352. }
  353. return pbDecryptedMessage;
  354. }
  355. //
  356. // End section from Money team
  357. //
  358. /*++
  359. Patch the Decrypt entry point.
  360. --*/
  361. CRITICAL_SECTION g_csPatch;
  362. DWORD g_dwDecrypt = (DWORD_PTR)&Decrypt;
  363. HINSTANCE
  364. APIHOOK(LoadLibraryA)(
  365. LPCSTR lpLibFileName
  366. )
  367. {
  368. HMODULE hMod = ORIGINAL_API(LoadLibraryA)(lpLibFileName);
  369. //
  370. // Wrap the patch in a critical section so we know the library won't be
  371. // freed underneath us
  372. //
  373. EnterCriticalSection(&g_csPatch);
  374. HMODULE hMoney = GetModuleHandleW(L"mnyutil.dll");
  375. if (hMoney) {
  376. // Patch the dll with a jump to our function
  377. LPBYTE lpProc = (LPBYTE) GetProcAddress(hMoney, (LPCSTR)290);
  378. if (lpProc) {
  379. __try {
  380. DWORD dwOldProtect;
  381. if (VirtualProtect((PVOID)lpProc, 5, PAGE_READWRITE, &dwOldProtect)) {
  382. *(WORD *)lpProc = 0x25ff; lpProc += 2;
  383. *(DWORD *)lpProc = (DWORD_PTR)&g_dwDecrypt;
  384. }
  385. } __except(1) {
  386. LOGN(eDbgLevelError, "[LoadLibraryA] Exception while patching entry point");
  387. }
  388. }
  389. }
  390. LeaveCriticalSection(&g_csPatch);
  391. return hMod;
  392. }
  393. BOOL
  394. APIHOOK(FreeLibrary)(
  395. HMODULE hModule
  396. )
  397. {
  398. EnterCriticalSection(&g_csPatch);
  399. BOOL bRet = ORIGINAL_API(FreeLibrary)(hModule);
  400. LeaveCriticalSection(&g_csPatch);
  401. return bRet;
  402. }
  403. /*++
  404. Register hooked functions
  405. --*/
  406. BOOL
  407. NOTIFY_FUNCTION(
  408. DWORD fdwReason
  409. )
  410. {
  411. if (fdwReason == DLL_PROCESS_ATTACH) {
  412. if (!InitializeCriticalSectionAndSpinCount(&g_csPatch, 0x80000000)) {
  413. LOGN(eDbgLevelError, "[NotifyFn] Failed to initialize critical section");
  414. return FALSE;
  415. }
  416. }
  417. return TRUE;
  418. }
  419. HOOK_BEGIN
  420. CALL_NOTIFY_FUNCTION
  421. APIHOOK_ENTRY(KERNEL32.DLL, LoadLibraryA)
  422. APIHOOK_ENTRY(KERNEL32.DLL, FreeLibrary)
  423. HOOK_END
  424. IMPLEMENT_SHIM_END