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.

539 lines
14 KiB

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