Dienstag, 12. Januar 2010

Houston, we have a key

I finally got some time to hack around in the source code of wine to allow it to dump the key that will be imported. This hacky patch is capable of dumping the private RSA key that will be used for exchanging the RC4 key that will be used during client and server communication.

diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c
index 665bc40..9c9dd5e 100644
--- a/dlls/rsaenh/rsaenh.c
+++ b/dlls/rsaenh/rsaenh.c
@@ -3016,9 +3016,16 @@ static BOOL import_key(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen,
 BOOL WINAPI RSAENH_CPImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen,
                                HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey)
 {
+    DWORD i;
     TRACE("(hProv=%08lx, pbData=%p, dwDataLen=%d, hPubKey=%08lx, dwFlags=%08x, phKey=%p)\n",
         hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);

+    if (pbData && dwDataLen > 0) {
+        for (i = 0; i < dwDataLen; i++) {
+            printf("0x%02x (%d)\n", pbData[i], pbData[i]);
+       }
+    }
+
     if (dwFlags & CRYPT_IPSEC_HMAC_KEY)
     {
         FIXME("unimplemented for CRYPT_IPSEC_HMAC_KEY\n");
This patch dumps the 308 bytes of data that are the exported private key. So you are wondering how the private key looks like?
0x07 (7)
0x02 (2)
0x00 (0)
0x00 (0)
0x00 (0)
0xa4 (164)
0x00 (0)
0x00 (0)
0x52 (82)
0x53 (83)
0x41 (65)
0x32 (50)
0x00 (0)
0x02 (2)
0x00 (0)
0x00 (0)
0x01 (1)
0x00 (0)
0x00 (0)
0x00 (0)
0xab (171)
0xef (239)
0xfa (250)
0xc6 (198)
0x7d (125)
0xe8 (232)
0xde (222)
0xfb (251)
0x68 (104)
0x38 (56)
0x09 (9)
0x92 (146)
0xd9 (217)
0x42 (66)
0x7e (126)
0x6b (107)
0x89 (137)
0x9e (158)
0x21 (33)
0xd7 (215)
0x52 (82)
0x1c (28)
0x99 (153)
0x3c (60)
0x17 (23)
0x48 (72)
0x4e (78)
0x3a (58)
0x44 (68)
0x02 (2)
0xf2 (242)
0xfa (250)
0x74 (116)
0x57 (87)
0xda (218)
0xe4 (228)
0xd3 (211)
0xc0 (192)
0x35 (53)
0x67 (103)
0xfa (250)
0x6e (110)
0xdf (223)
0x78 (120)
0x4c (76)
0x75 (117)
0x35 (53)
0x1c (28)
0xa0 (160)
0x74 (116)
0x49 (73)
0xe3 (227)
0x20 (32)
0x13 (19)
0x71 (113)
0x35 (53)
0x65 (101)
0xdf (223)
0x12 (18)
0x20 (32)
0xf5 (245)
0xf5 (245)
0xf5 (245)
0xc1 (193)
0xed (237)
0x5c (92)
0x91 (145)
0x36 (54)
0x75 (117)
0xb0 (176)
0xa9 (169)
0x9c (156)
0x04 (4)
0xdb (219)
0x0c (12)
0x8c (140)
0xbf (191)
0x99 (153)
0x75 (117)
0x13 (19)
0x7e (126)
0x87 (135)
0x80 (128)
0x4b (75)
0x71 (113)
0x94 (148)
0xb8 (184)
0x00 (0)
0xa0 (160)
0x7d (125)
0xb7 (183)
0x53 (83)
0xdd (221)
0x20 (32)
0x63 (99)
0xee (238)
0xf7 (247)
0x83 (131)
0x41 (65)
0xfe (254)
0x16 (22)
0xa7 (167)
0x6e (110)
0xdf (223)
0x21 (33)
0x7d (125)
0x76 (118)
0xc0 (192)
0x85 (133)
0xd5 (213)
0x65 (101)
0x7f (127)
0x00 (0)
0x23 (35)
0x57 (87)
0x45 (69)
0x52 (82)
0x02 (2)
0x9d (157)
0xea (234)
0x69 (105)
0xac (172)
0x1f (31)
0xfd (253)
0x3f (63)
0x8c (140)
0x4a (74)
0xd0 (208)
0x01 (1)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x01 (1)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x64 (100)
0xd5 (213)
0xaa (170)
0xb1 (177)
0xa6 (166)
0x03 (3)
0x18 (24)
0x92 (146)
0x03 (3)
0xaa (170)
0x31 (49)
0x2e (46)
0x48 (72)
0x4b (75)
0x65 (101)
0x20 (32)
0x99 (153)
0xcd (205)
0xc6 (198)
0x0c (12)
0x15 (21)
0x0c (12)
0xbf (191)
0x3e (62)
0xff (255)
0x78 (120)
0x95 (149)
0x67 (103)
0xb1 (177)
0x74 (116)
0x5b (91)
0x60 (96)
0x01 (1)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
0x00 (0)
The first 20 bytes are header data and the rest is the key. This is really good! Now we can use the private key to generate a public key from it. But we need to code to recreated this key first. I reengineerd the code and it looks like this:
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>

static void byte_dump(CONST BYTE * pbData, DWORD dwDataLen) {
 DWORD i;
 if (pbData && dwDataLen > 0) {
  for (i = 0; i < dwDataLen; i++) {
   printf("0x%02x (%d)\n", pbData[i], pbData[i]);
  }
 }
}

int main() {

 BLOBHEADER header;
 header.bType = 0x7; /* PRIVATEKEYBLOB */
 header.bVersion = 2; /* Must be 2 */
 header.reserved = 0; /* Must be 0 */
 header.aiKeyAlg = 0xa400;
 byte_dump((CONST BYTE *) &header, sizeof(BLOBHEADER));

 RSAPUBKEY rsaPubKey;
 rsaPubKey.magic = 0x32415352; /* RSAENH_MAGIC_RSA2 */
 rsaPubKey.bitlen = 0x00000200; /* 512 bit long */
 rsaPubKey.pubexp = 0x00000001;
 byte_dump((CONST BYTE *) &rsaPubKey, sizeof(RSAPUBKEY));

 BYTE pbSrc[288] = {
  0xab, 0xef, 0xfa, 0xc6,
  0x7d, 0xe8, 0xde, 0xfb, 0x68, 0x38, 0x09, 0x92,
  0xd9, 0x42, 0x7e, 0x6b, 0x89, 0x9e, 0x21, 0xd7,
  0x52, 0x1c, 0x99, 0x3c, 0x17, 0x48, 0x4e, 0x3a,
  0x44, 0x02, 0xf2, 0xfa, 0x74, 0x57, 0xda, 0xe4,
  0xd3, 0xc0, 0x35, 0x67, 0xfa, 0x6e, 0xdf, 0x78,
  0x4c, 0x75, 0x35, 0x1c, 0xa0, 0x74, 0x49, 0xe3,
  0x20, 0x13, 0x71, 0x35, 0x65, 0xdf, 0x12, 0x20,
  0xf5, 0xf5, 0xf5, 0xc1, 0xed, 0x5c, 0x91, 0x36,
  0x75, 0xb0, 0xa9, 0x9c, 0x04, 0xdb, 0x0c, 0x8c,
  0xbf, 0x99, 0x75, 0x13, 0x7e, 0x87, 0x80, 0x4b,
  0x71, 0x94, 0xb8, 0x00, 0xa0, 0x7d, 0xb7, 0x53,
  0xdd, 0x20, 0x63, 0xee, 0xf7, 0x83, 0x41, 0xfe,
  0x16, 0xa7, 0x6e, 0xdf, 0x21, 0x7d, 0x76, 0xc0,
  0x85, 0xd5, 0x65, 0x7f, 0x00, 0x23, 0x57, 0x45,
  0x52, 0x02, 0x9d, 0xea, 0x69, 0xac, 0x1f, 0xfd,
  0x3f, 0x8c, 0x4a, 0xd0, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x64, 0xd5, 0xaa, 0xb1,
  0xa6, 0x03, 0x18, 0x92, 0x03, 0xaa, 0x31, 0x2e,
  0x48, 0x4b, 0x65, 0x20, 0x99, 0xcd, 0xc6, 0x0c,
  0x15, 0x0c, 0xbf, 0x3e, 0xff, 0x78, 0x95, 0x67,
  0xb1, 0x74, 0x5b, 0x60, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00
 };
 byte_dump((CONST BYTE *) &pbSrc, 288);
}
Now we can pass this to CPImportKey and calculate the public (which is always possible from the private key). But first I need to figure out how to do so using the wincrypt API. Once we've done that we can do the following things.
  1. Create a server component that is using the public key to decrypt the packages passed to it.
  2. Dump what is returned by CryptGenRandom
  3. Find out what CryptCreateHash does and especially why it is used here
  4. Dump what is encrypted by CryptEncrypt
  5. Hack wine to use a faked public key that is imported during the second CPImportKey (as there is no way to calculate the private key for this)
There are much more things that will need to be done, but again we solved another mystery. Oh, and here is the dump of the import of the public key:
0x06 (6)
0x02 (2)
0x00 (0)
0x00 (0)
0x00 (0)
0xa4 (164)
0x00 (0)
0x00 (0)
0x52 (82)
0x53 (83)
0x41 (65)
0x31 (49)
0x00 (0)
0x04 (4)
0x00 (0)
0x00 (0)
0x01 (1)
0x00 (0)
0x01 (1)
0x00 (0)
0x4d (77)
0x03 (3)
0x8d (141)
0xd7 (215)
0xd8 (216)
0xa8 (168)
0x85 (133)
0x97 (151)
0x2d (45)
0x04 (4)
0xde (222)
0x57 (87)
0xe2 (226)
0x77 (119)
0xc4 (196)
0xbf (191)
0xc6 (198)
0x13 (19)
0x15 (21)
0x0e (14)
0x26 (38)
0x72 (114)
0x99 (153)
0x11 (17)
0xa1 (161)
0xcd (205)
0xf3 (243)
0x8f (143)
0xd5 (213)
0x5d (93)
0x63 (99)
0x4c (76)
0xf3 (243)
0x75 (117)
0xb7 (183)
0x62 (98)
0x9d (157)
0xee (238)
0xe8 (232)
0xd5 (213)
0xc5 (197)
0xa7 (167)
0x0e (14)
0x3c (60)
0x9c (156)
0x51 (81)
0xd4 (212)
0x3f (63)
0x00 (0)
0x45 (69)
0xb2 (178)
0xed (237)
0x19 (25)
0xb1 (177)
0xca (202)
0xda (218)
0x84 (132)
0x1c (28)
0x6b (107)
0x35 (53)
0x41 (65)
0x17 (23)
0x46 (70)
0xd0 (208)
0x56 (86)
0xb9 (185)
0x4c (76)
0x06 (6)
0xcd (205)
0x8d (141)
0xc5 (197)
0x50 (80)
0x39 (57)
0x36 (54)
0x4e (78)
0xe3 (227)
0x9b (155)
0x5e (94)
0x3c (60)
0x44 (68)
0xe8 (232)
0x04 (4)
0x0e (14)
0x90 (144)
0xc4 (196)
0x89 (137)
0xfc (252)
0x24 (36)
0xe9 (233)
0xc4 (196)
0xff (255)
0xc6 (198)
0x97 (151)
0xfd (253)
0xd6 (214)
0x5d (93)
0x2b (43)
0x67 (103)
0x5c (92)
0xa2 (162)
0x7f (127)
0x8d (141)
0x2a (42)
0xb9 (185)
0x5a (90)
0x52 (82)
0x3c (60)
0xec (236)
0x0d (13)
0xc1 (193)
0x55 (85)
0xc8 (200)
0xc1 (193)
0xb0 (176)
0x07 (7)
0x3a (58)
0xdc (220)
0x03 (3)
0x9c (156)
0x38 (56)
0x34 (52)
0x08 (8)
0x0e (14)
0x19 (25)
0x27 (39)
0xcd (205)
0x7b (123)
0xd0 (208)
Oh, and here is the code to dump the private key of the client and the public key of the server.
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>

static void byte_dump(CONST BYTE * pbData, DWORD dwDataLen) {
 DWORD i;
 if (pbData && dwDataLen > 0) {
  for (i = 0; i < dwDataLen; i++) {
   printf("0x%02x (%d)\n", pbData[i], pbData[i]);
  }
 }
}

static void dump_private_key() {
 BLOBHEADER header;
 header.bType = 0x7; /* PRIVATEKEYBLOB */
 header.bVersion = 2; /* Must be 2 */
 header.reserved = 0; /* Must be 0 */
 header.aiKeyAlg = 0xa400;
 byte_dump((CONST BYTE *) &header, sizeof(BLOBHEADER));

 RSAPUBKEY rsaPubKey;
 rsaPubKey.magic = 0x32415352; /* RSAENH_MAGIC_RSA2 */
 rsaPubKey.bitlen = 0x00000200; /* 512 bit long */
 rsaPubKey.pubexp = 0x00000001;
 byte_dump((CONST BYTE *) &rsaPubKey, sizeof(RSAPUBKEY));

 BYTE pbSrc[288] = {
  0xab, 0xef, 0xfa, 0xc6,
  0x7d, 0xe8, 0xde, 0xfb, 0x68, 0x38, 0x09, 0x92,
  0xd9, 0x42, 0x7e, 0x6b, 0x89, 0x9e, 0x21, 0xd7,
  0x52, 0x1c, 0x99, 0x3c, 0x17, 0x48, 0x4e, 0x3a,
  0x44, 0x02, 0xf2, 0xfa, 0x74, 0x57, 0xda, 0xe4,
  0xd3, 0xc0, 0x35, 0x67, 0xfa, 0x6e, 0xdf, 0x78,
  0x4c, 0x75, 0x35, 0x1c, 0xa0, 0x74, 0x49, 0xe3,
  0x20, 0x13, 0x71, 0x35, 0x65, 0xdf, 0x12, 0x20,
  0xf5, 0xf5, 0xf5, 0xc1, 0xed, 0x5c, 0x91, 0x36,
  0x75, 0xb0, 0xa9, 0x9c, 0x04, 0xdb, 0x0c, 0x8c,
  0xbf, 0x99, 0x75, 0x13, 0x7e, 0x87, 0x80, 0x4b,
  0x71, 0x94, 0xb8, 0x00, 0xa0, 0x7d, 0xb7, 0x53,
  0xdd, 0x20, 0x63, 0xee, 0xf7, 0x83, 0x41, 0xfe,
  0x16, 0xa7, 0x6e, 0xdf, 0x21, 0x7d, 0x76, 0xc0,
  0x85, 0xd5, 0x65, 0x7f, 0x00, 0x23, 0x57, 0x45,
  0x52, 0x02, 0x9d, 0xea, 0x69, 0xac, 0x1f, 0xfd,
  0x3f, 0x8c, 0x4a, 0xd0, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x64, 0xd5, 0xaa, 0xb1,
  0xa6, 0x03, 0x18, 0x92, 0x03, 0xaa, 0x31, 0x2e,
  0x48, 0x4b, 0x65, 0x20, 0x99, 0xcd, 0xc6, 0x0c,
  0x15, 0x0c, 0xbf, 0x3e, 0xff, 0x78, 0x95, 0x67,
  0xb1, 0x74, 0x5b, 0x60, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00
 };
 byte_dump((CONST BYTE *) &pbSrc, 288);
}

static void dump_public_key() {
 BLOBHEADER header;
 header.bType = 0x6; /* PUBLICKEYBLOB */
 header.bVersion = 2; /* Must be 2 */
 header.reserved = 0; /* Must be 0 */
 header.aiKeyAlg = 0xa400;
 byte_dump((CONST BYTE *) &header, sizeof(BLOBHEADER));

 RSAPUBKEY rsaPubKey;
 rsaPubKey.magic = 0x32415352; /* RSAENH_MAGIC_RSA2 */
 rsaPubKey.bitlen = 0x00000400; /* 512 bit long */
 rsaPubKey.pubexp = 0x00010001;
 byte_dump((CONST BYTE *) &rsaPubKey, sizeof(RSAPUBKEY));

 BYTE pbSrc[128] = {
  0x4d, 0x03, 0x8d, 0xd7, 0xd8, 0xa8, 0x85, 0x97,
  0x2d, 0x04, 0xde, 0x57, 0xe2, 0x77, 0xc4, 0xbf,
  0xc6, 0x13, 0x15, 0x0e, 0x26, 0x72, 0x99, 0x11,
  0xa1, 0xcd, 0xf3, 0x8f, 0xd5, 0x5d, 0x63, 0x4c,
  0xf3, 0x75, 0xb7, 0x62, 0x9d, 0xee, 0xe8, 0xd5,
  0xc5, 0xa7, 0x0e, 0x3c, 0x9c, 0x51, 0xd4, 0x3f,
  0x00, 0x45, 0xb2, 0xed, 0x19, 0xb1, 0xca, 0xda,
  0x84, 0x1c, 0x6b, 0x35, 0x41, 0x17, 0x46, 0xd0,
  0x56, 0xb9, 0x4c, 0x06, 0xcd, 0x8d, 0xc5, 0x50,
  0x39, 0x36, 0x4e, 0xe3, 0x9b, 0x5e, 0x3c, 0x44,
  0xe8, 0x04, 0x0e, 0x90, 0xc4, 0x89, 0xfc, 0x24,
  0xe9, 0xc4, 0xff, 0xc6, 0x97, 0xfd, 0xd6, 0x5d,
  0x2b, 0x67, 0x5c, 0xa2, 0x7f, 0x8d, 0x2a, 0xb9,
  0x5a, 0x52, 0x3c, 0xec, 0x0d, 0xc1, 0x55, 0xc8,
  0xc1, 0xb0, 0x07, 0x3a, 0xdc, 0x03, 0x9c, 0x38,
  0x34, 0x08, 0x0e, 0x19, 0x27, 0xcd, 0x7b, 0xd0
 };
 byte_dump((CONST BYTE *) &pbSrc, 128);
}

int main() {
 dump_private_key();
 printf("\n");
 dump_public_key();
}
So it looks to me that:
  1. The client has it's own private and public RSA-keyset
  2. The server has a different RSA-one, too
  3. These keys are used to exchange the symetric RC4 key

It is really getting complicated.

Keine Kommentare:

Kommentar veröffentlichen