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.

704 lines
20 KiB

  1. #include <windows.h>
  2. #include "crc32.h"
  3. #include "chksect.h"
  4. #define CHECK_SECTION
  5. #ifndef offsetof
  6. #define offsetof(s,m) (size_t)&(((s *)0)->m)
  7. #endif
  8. #define RoundUp(n,scale) (scale * ((n + scale - 1) / scale))
  9. #define IsMemZero(pv,cb) (!(*((char *)pv) || memcmp(pv,((char *)pv)+1,cb-1)))
  10. #pragma intrinsic(memcpy,memcmp)
  11. enum
  12. {
  13. EX_CHECKSUM,
  14. EX_SECURITY,
  15. EX_CRC32FILE,
  16. EX_EOF,
  17. MAX_EXCLUDE
  18. };
  19. #define MAX_BUFFER (256*1024) /* must be even */
  20. typedef struct
  21. {
  22. DWORD signature;
  23. DWORD crc32File;
  24. DWORD cbCabFile;
  25. } SELFTEST_SECTION;
  26. #define SECTION_NAME "Ext_Cab1"
  27. #define SECTION_SIGNATURE (0x4D584653)
  28. #ifdef ADD_SECTION
  29. SELFTEST_RESULT AddSection(char *pszEXEFileName,char *pszCABFileName)
  30. #else
  31. #ifdef CHECK_SECTION
  32. SELFTEST_RESULT CheckSection(char *pszEXEFileName)
  33. #else
  34. SELFTEST_RESULT SelfTest(char *pszEXEFileName,
  35. unsigned long *poffCabinet,unsigned long *pcbCabinet)
  36. #endif
  37. #endif
  38. {
  39. HANDLE hFile; // handle to the file we're updating
  40. enum SELFTEST_RESULT result; // our return code
  41. union
  42. {
  43. IMAGE_DOS_HEADER dos;
  44. IMAGE_NT_HEADERS nt;
  45. IMAGE_SECTION_HEADER section;
  46. } header; // used to examine the file
  47. DWORD offNTHeader; // file offset to NT header
  48. int cSections; // number of sections in the file
  49. unsigned char *pBuffer; // general-purpose buffer
  50. DWORD cbActual; // # of bytes actual read/written
  51. #ifndef CHECK_SECTION
  52. unsigned long crc32; // computed CRC-32
  53. struct
  54. {
  55. DWORD offExclude;
  56. DWORD cbExclude;
  57. } excludeList[MAX_EXCLUDE]; // list of ranges to exclude from CRC
  58. int iExclude; // exclude list index
  59. DWORD offSelfTestSection; // file offset of our added section
  60. SELFTEST_SECTION SelfTestSection; // added section header
  61. DWORD cbFile; // number of bytes in file/region
  62. DWORD cbChunk; // number of bytes in current chunk
  63. DWORD offFile; // current file offset
  64. #endif
  65. #ifdef ADD_SECTION
  66. DWORD offSectionHeader; // file offset of section header
  67. DWORD offMaxVirtualAddress; // lowest unused virtual address
  68. DWORD cbAlignVirtual; // virtual address alignment increment
  69. DWORD cbAlignFile; // file address alignment increment
  70. HANDLE hCABFile; // cabinet file handle
  71. DWORD cbCABFile; // cabinet file size
  72. DWORD checksum; // generated checksum
  73. WORD *pBufferW; // used to generate checksum
  74. #endif
  75. #ifdef CHECK_SECTION
  76. DWORD offSectionHeaderEnd; // first unused byte after section headers
  77. DWORD offFirstSection; // first used byte after that
  78. DWORD offImportStart; // where the import entries start
  79. DWORD cbImport; // size of import entry data
  80. #endif
  81. #ifndef CHECK_SECTION
  82. GenerateCRC32Table();
  83. #endif
  84. pBuffer = (void *) GlobalAlloc(GMEM_FIXED,MAX_BUFFER);
  85. if (pBuffer == NULL)
  86. {
  87. result = SELFTEST_NO_MEMORY;
  88. goto done_no_buffer;
  89. }
  90. #ifdef ADD_SECTION
  91. /* get size of cabinet */
  92. hCABFile = CreateFile(pszCABFileName,GENERIC_READ,FILE_SHARE_READ,NULL,
  93. OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
  94. if (hCABFile == INVALID_HANDLE_VALUE)
  95. {
  96. result = SELFTEST_FILE_NOT_FOUND;
  97. goto done_no_cab;
  98. }
  99. cbCABFile = GetFileSize(hCABFile,NULL);
  100. #endif
  101. /* open EXE image */
  102. #ifdef ADD_SECTION
  103. hFile = CreateFile(pszEXEFileName,GENERIC_READ|GENERIC_WRITE,0,NULL,
  104. OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
  105. #else
  106. hFile = CreateFile(pszEXEFileName,GENERIC_READ,FILE_SHARE_READ,NULL,
  107. OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
  108. #endif
  109. if (hFile == INVALID_HANDLE_VALUE)
  110. {
  111. result = SELFTEST_FILE_NOT_FOUND;
  112. goto done_no_exe;
  113. }
  114. /* read MS-DOS header */
  115. if ((ReadFile(hFile,&header.dos,sizeof(IMAGE_DOS_HEADER),&cbActual,NULL) != TRUE)
  116. || (cbActual != sizeof(IMAGE_DOS_HEADER)))
  117. {
  118. result = SELFTEST_READ_ERROR;
  119. goto done;
  120. }
  121. if (header.dos.e_magic != IMAGE_DOS_SIGNATURE)
  122. {
  123. offNTHeader = 0;
  124. }
  125. else
  126. {
  127. offNTHeader = header.dos.e_lfanew;
  128. }
  129. /* read PE header */
  130. SetFilePointer(hFile,offNTHeader,NULL,FILE_BEGIN);
  131. if ((ReadFile(hFile,&header.nt,sizeof(IMAGE_NT_HEADERS),&cbActual,NULL) != TRUE)
  132. || (cbActual != sizeof(IMAGE_NT_HEADERS)))
  133. {
  134. result = SELFTEST_READ_ERROR;
  135. goto done;
  136. }
  137. if (header.nt.Signature != IMAGE_NT_SIGNATURE)
  138. {
  139. result = SELFTEST_NOT_PE_FILE;
  140. goto done;
  141. }
  142. cSections = header.nt.FileHeader.NumberOfSections;
  143. #ifdef ADD_SECTION
  144. cbAlignVirtual = header.nt.OptionalHeader.SectionAlignment;
  145. cbAlignFile = header.nt.OptionalHeader.FileAlignment;
  146. offMaxVirtualAddress = 0;
  147. #endif
  148. #ifndef CHECK_SECTION
  149. /* determine current file size */
  150. cbFile = GetFileSize(hFile,NULL);
  151. if (cbFile == 0xFFFFFFFF)
  152. {
  153. result = SELFTEST_READ_ERROR;
  154. goto done;
  155. }
  156. #endif
  157. #ifndef CHECK_SECTION
  158. /* see if we've been signed */
  159. if (header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress != 0)
  160. {
  161. #ifdef ADD_SECTION
  162. result = SELFTEST_SIGNED;
  163. goto done;
  164. #else
  165. /* make sure certificate is at the end of the file */
  166. if (cbFile !=
  167. (header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress
  168. + header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size))
  169. {
  170. result = SELFTEST_FAILED;
  171. goto done;
  172. }
  173. else
  174. {
  175. /* ignore anything starting at the certificate */
  176. cbFile = header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
  177. }
  178. #endif
  179. }
  180. #endif
  181. #ifdef ADD_SECTION
  182. /* determine lowest un-used virtual address */
  183. #else
  184. /* locate our added section */
  185. #endif
  186. #ifndef CHECK_SECTION
  187. offSelfTestSection = 0;
  188. #endif
  189. #ifdef ADD_SECTION
  190. offSectionHeader = offNTHeader +
  191. sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) +
  192. header.nt.FileHeader.SizeOfOptionalHeader +
  193. cSections * sizeof(IMAGE_SECTION_HEADER);
  194. #endif
  195. SetFilePointer(hFile,(offNTHeader + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) +
  196. header.nt.FileHeader.SizeOfOptionalHeader),NULL,FILE_BEGIN);
  197. #ifdef CHECK_SECTION
  198. offSectionHeaderEnd = offNTHeader +
  199. sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) +
  200. header.nt.FileHeader.SizeOfOptionalHeader +
  201. cSections * sizeof(IMAGE_SECTION_HEADER);
  202. offImportStart = header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress;
  203. cbImport = header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size;
  204. if ((ReadFile(hFile,&header.section,sizeof(IMAGE_SECTION_HEADER),&cbActual,NULL) != TRUE)
  205. || (cbActual != sizeof(IMAGE_SECTION_HEADER)))
  206. {
  207. result = SELFTEST_READ_ERROR;
  208. goto done;
  209. }
  210. offFirstSection = header.section.PointerToRawData;
  211. if ((offFirstSection - offSectionHeaderEnd) > 0)
  212. {
  213. SetFilePointer(hFile,offSectionHeaderEnd,NULL,FILE_BEGIN);
  214. if ((ReadFile(hFile,pBuffer,(offFirstSection - offSectionHeaderEnd),&cbActual,NULL) != TRUE)
  215. || (cbActual != (DWORD) (offFirstSection - offSectionHeaderEnd)))
  216. {
  217. result = SELFTEST_READ_ERROR;
  218. goto done;
  219. }
  220. if ((offImportStart >= offSectionHeaderEnd) &&
  221. ((offImportStart + cbImport) <= offFirstSection))
  222. {
  223. memset(pBuffer + (offImportStart - offSectionHeaderEnd),0,cbImport);
  224. }
  225. if ((*pBuffer != '\0') ||
  226. (((offFirstSection - offSectionHeaderEnd) > 1) &&
  227. (memcmp(pBuffer,pBuffer + 1,(offFirstSection - offSectionHeaderEnd - 1)) != 0)))
  228. {
  229. result = SELFTEST_DIRTY;
  230. }
  231. else
  232. {
  233. result = SELFTEST_NO_ERROR;
  234. }
  235. }
  236. else
  237. {
  238. result = SELFTEST_NO_ERROR;
  239. }
  240. #else
  241. while (cSections--)
  242. {
  243. if ((ReadFile(hFile,&header.section,sizeof(IMAGE_SECTION_HEADER),&cbActual,NULL) != TRUE)
  244. || (cbActual != sizeof(IMAGE_SECTION_HEADER)))
  245. {
  246. result = SELFTEST_READ_ERROR;
  247. goto done;
  248. }
  249. if (!memcmp(header.section.Name,SECTION_NAME,sizeof(header.section.Name)))
  250. {
  251. /* found our added section */
  252. #ifdef ADD_SECTION
  253. result = SELFTEST_ALREADY;
  254. goto done;
  255. #else
  256. offSelfTestSection = header.section.PointerToRawData;
  257. break;
  258. #endif
  259. }
  260. #ifdef ADD_SECTION
  261. if (offMaxVirtualAddress <
  262. (header.section.VirtualAddress + header.section.Misc.VirtualSize))
  263. {
  264. offMaxVirtualAddress =
  265. (header.section.VirtualAddress + header.section.Misc.VirtualSize);
  266. }
  267. #endif
  268. }
  269. #ifdef ADD_SECTION
  270. /* increase number of sections in the file; whack checksum */
  271. SetFilePointer(hFile,offNTHeader,NULL,FILE_BEGIN);
  272. if ((ReadFile(hFile,&header.nt,sizeof(IMAGE_NT_HEADERS),&cbActual,NULL) != TRUE)
  273. || (cbActual != sizeof(IMAGE_NT_HEADERS)))
  274. {
  275. result = SELFTEST_READ_ERROR;
  276. goto done;
  277. }
  278. header.nt.FileHeader.NumberOfSections++;
  279. header.nt.OptionalHeader.CheckSum = 0;
  280. header.nt.OptionalHeader.SizeOfImage =
  281. RoundUp(offMaxVirtualAddress,cbAlignVirtual) +
  282. RoundUp((sizeof(SELFTEST_SECTION) + cbCABFile),cbAlignVirtual);
  283. SetFilePointer(hFile,offNTHeader,NULL,FILE_BEGIN);
  284. if ((WriteFile(hFile,&header.nt,sizeof(IMAGE_NT_HEADERS),&cbActual,NULL) != TRUE)
  285. || (cbActual != sizeof(IMAGE_NT_HEADERS)))
  286. {
  287. result = SELFTEST_WRITE_ERROR;
  288. goto done;
  289. }
  290. /* make sure there's room for another section header */
  291. SetFilePointer(hFile,offSectionHeader,NULL,FILE_BEGIN);
  292. if ((ReadFile(hFile,&header.section,sizeof(IMAGE_SECTION_HEADER),&cbActual,NULL) != TRUE)
  293. || (cbActual != sizeof(IMAGE_SECTION_HEADER)))
  294. {
  295. result = SELFTEST_READ_ERROR;
  296. goto done;
  297. }
  298. if (!IsMemZero(&header.section,sizeof(IMAGE_SECTION_HEADER)))
  299. {
  300. result = SELFTEST_NO_SECTION;
  301. goto done;
  302. }
  303. /* create the new section header */
  304. memcpy(header.section.Name,SECTION_NAME,sizeof(header.section.Name));
  305. header.section.SizeOfRawData =
  306. RoundUp((sizeof(SELFTEST_SECTION) + cbCABFile),cbAlignFile);
  307. header.section.PointerToRawData =
  308. RoundUp(cbFile,cbAlignFile);
  309. header.section.VirtualAddress =
  310. RoundUp(offMaxVirtualAddress,cbAlignVirtual);
  311. header.section.Misc.VirtualSize =
  312. RoundUp((sizeof(SELFTEST_SECTION) + cbCABFile),cbAlignVirtual);
  313. header.section.Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
  314. IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ);
  315. /* write the new section header */
  316. SetFilePointer(hFile,offSectionHeader,NULL,FILE_BEGIN);
  317. if ((WriteFile(hFile,&header.section,sizeof(IMAGE_SECTION_HEADER),&cbActual,NULL) != TRUE)
  318. || (cbActual != sizeof(IMAGE_SECTION_HEADER)))
  319. {
  320. result = SELFTEST_WRITE_ERROR;
  321. goto done;
  322. }
  323. /* create the new section data */
  324. memset(&SelfTestSection,0,sizeof(SelfTestSection));
  325. SelfTestSection.signature = SECTION_SIGNATURE;
  326. SelfTestSection.cbCabFile = cbCABFile;
  327. offSelfTestSection = header.section.PointerToRawData;
  328. SetFilePointer(hFile,offSelfTestSection,NULL,FILE_BEGIN);
  329. if ((WriteFile(hFile,&SelfTestSection,sizeof(SelfTestSection),&cbActual,NULL) != TRUE)
  330. || (cbActual != sizeof(SelfTestSection)))
  331. {
  332. result = SELFTEST_WRITE_ERROR;
  333. goto done;
  334. }
  335. /* copy cabinet into section */
  336. SetFilePointer(hCABFile,0,NULL,FILE_BEGIN);
  337. cbFile = cbCABFile;
  338. while (cbFile)
  339. {
  340. if (cbFile > MAX_BUFFER)
  341. {
  342. cbChunk = MAX_BUFFER;
  343. }
  344. else
  345. {
  346. cbChunk = cbFile;
  347. }
  348. if ((ReadFile(hCABFile,pBuffer,cbChunk,&cbActual,NULL) != TRUE)
  349. || (cbActual != cbChunk))
  350. {
  351. result = SELFTEST_READ_ERROR;
  352. goto done;
  353. }
  354. if ((WriteFile(hFile,pBuffer,cbChunk,&cbActual,NULL) != TRUE)
  355. || (cbActual != cbChunk))
  356. {
  357. result = SELFTEST_WRITE_ERROR;
  358. }
  359. cbFile -= cbChunk;
  360. }
  361. /* pad added section as needed */
  362. cbChunk = header.section.SizeOfRawData - sizeof(SelfTestSection) - cbCABFile;
  363. if (cbChunk != 0)
  364. {
  365. memset(pBuffer,0,cbChunk);
  366. if ((WriteFile(hFile,pBuffer,cbChunk,&cbActual,NULL) != TRUE)
  367. || (cbActual != cbChunk))
  368. {
  369. result = SELFTEST_WRITE_ERROR;
  370. }
  371. }
  372. /* we've now increased total size of the file */
  373. cbFile = offSelfTestSection + header.section.SizeOfRawData;
  374. #else
  375. /* make sure our added section was found */
  376. if (offSelfTestSection == 0)
  377. {
  378. result = SELFTEST_NO_SECTION;
  379. goto done;
  380. }
  381. #endif
  382. /* If this EXE gets signed, the checksum will be changed. */
  383. excludeList[EX_CHECKSUM].offExclude = offNTHeader +
  384. offsetof(IMAGE_NT_HEADERS,OptionalHeader.CheckSum);
  385. excludeList[EX_CHECKSUM].cbExclude =
  386. sizeof(header.nt.OptionalHeader.CheckSum);
  387. /* If this EXE gets signed, the security entry will be changed. */
  388. excludeList[EX_SECURITY].offExclude = offNTHeader +
  389. offsetof(IMAGE_NT_HEADERS,
  390. OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);
  391. excludeList[EX_SECURITY].cbExclude = sizeof(IMAGE_DATA_DIRECTORY);
  392. /* Can't CRC our own CRC field. */
  393. excludeList[EX_CRC32FILE].offExclude = offSelfTestSection +
  394. offsetof(SELFTEST_SECTION,crc32File);
  395. excludeList[EX_CRC32FILE].cbExclude = sizeof(SelfTestSection.crc32File);
  396. /* Stop at end of known file. */
  397. /* Note: current code assumes that the only thing which could */
  398. /* be appended to the file after this is the certificate from */
  399. /* codesigning, and that it will be pointed at by the security */
  400. /* entry. If anything else appends, or padding is added before */
  401. /* the certificate, we'll have to store this file size in the */
  402. /* added section, and retrieve it before running the CRC. */
  403. excludeList[EX_EOF].offExclude = cbFile;
  404. /* Compute the CRC-32 of the file, skipping excluded extents. */
  405. /* This code assumes excludeList is sorted by offExclude. */
  406. crc32 = CRC32_INITIAL_VALUE;
  407. offFile = 0;
  408. #ifdef ADD_SECTION
  409. /* Along the way, compute the correct checksum for this new */
  410. /* image. We know that each of the sections on the exclude */
  411. /* list just happened to be zeroed right now, so they won't */
  412. /* affect our checksum. But we will have to add our new CRC32 */
  413. /* value to the checksum, because it will be in the file when */
  414. /* we're done. It helps that we know that all the exclusions */
  415. /* on the list are WORD aligned and have even lengths. */
  416. /* The checksum in a PE file is a 16-bit sum of 16-bit words */
  417. /* in the file, with wrap-around carry, while the checksum */
  418. /* field is filled with zero. The file's length is added, */
  419. /* yielding a 32-bit result. */
  420. checksum = 0;
  421. #endif
  422. for (iExclude = 0; iExclude < MAX_EXCLUDE; iExclude++)
  423. {
  424. SetFilePointer(hFile,offFile,NULL,FILE_BEGIN);
  425. cbFile = excludeList[iExclude].offExclude - offFile;
  426. while (cbFile)
  427. {
  428. if (cbFile > MAX_BUFFER)
  429. {
  430. cbChunk = MAX_BUFFER;
  431. }
  432. else
  433. {
  434. cbChunk = cbFile;
  435. }
  436. if ((ReadFile(hFile,pBuffer,cbChunk,&cbActual,NULL) != TRUE)
  437. || (cbActual != cbChunk))
  438. {
  439. result = SELFTEST_READ_ERROR;
  440. goto done;
  441. }
  442. CRC32Update(&crc32,pBuffer,cbChunk);
  443. offFile += cbChunk;
  444. cbFile -= cbChunk;
  445. #ifdef ADD_SECTION
  446. /* roll buffer into checksum */
  447. pBufferW = (WORD *) pBuffer;
  448. cbChunk >>= 1;
  449. while (cbChunk--)
  450. {
  451. checksum += *pBufferW++;
  452. if (checksum > 0x0000FFFF)
  453. {
  454. checksum -= 0x0000FFFF;
  455. }
  456. }
  457. #endif
  458. /*
  459. * INSERT PROGRESS GAUGE HERE:
  460. * %complete = (offFile * 100.0) / excludeList[EX_EOF].offExclude
  461. */
  462. }
  463. offFile += excludeList[iExclude].cbExclude;
  464. }
  465. #ifdef ADD_SECTION
  466. /* account for CRC32 value in checksum */
  467. checksum += (WORD) crc32;
  468. checksum += (crc32 >> 16);
  469. while (checksum > 0x0000FFFF)
  470. {
  471. checksum -= 0x0000FFFF;
  472. }
  473. /* add file length to checksum */
  474. checksum += excludeList[EX_EOF].offExclude;
  475. /* update CRC-32 value in added section */
  476. SetFilePointer(hFile,excludeList[EX_CRC32FILE].offExclude,NULL,FILE_BEGIN);
  477. if ((WriteFile(hFile,&crc32,sizeof(crc32),&cbActual,NULL) != TRUE)
  478. || (cbActual != sizeof(crc32)))
  479. {
  480. result = SELFTEST_WRITE_ERROR;
  481. goto done;
  482. }
  483. /* update checksum value in header */
  484. SetFilePointer(hFile,excludeList[EX_CHECKSUM].offExclude,NULL,FILE_BEGIN);
  485. if ((WriteFile(hFile,&checksum,sizeof(checksum),&cbActual,NULL) != TRUE)
  486. || (cbActual != sizeof(checksum)))
  487. {
  488. result = SELFTEST_WRITE_ERROR;
  489. goto done;
  490. }
  491. /* done */
  492. if (CloseHandle(hFile) != TRUE)
  493. {
  494. result = SELFTEST_WRITE_ERROR;
  495. }
  496. else
  497. {
  498. result = SELFTEST_NO_ERROR;
  499. }
  500. goto done_no_exe;
  501. #else
  502. /* read the header from the added section */
  503. SetFilePointer(hFile,offSelfTestSection,NULL,FILE_BEGIN);
  504. if ((ReadFile(hFile,&SelfTestSection,sizeof(SelfTestSection),&cbActual,NULL) != TRUE)
  505. || (cbActual != sizeof(SelfTestSection)))
  506. {
  507. result = SELFTEST_READ_ERROR;
  508. goto done;
  509. }
  510. /* verify CRC-32 value in added section */
  511. if ((SelfTestSection.signature != SECTION_SIGNATURE) ||
  512. (crc32 != SelfTestSection.crc32File))
  513. {
  514. result = SELFTEST_FAILED;
  515. }
  516. else
  517. {
  518. *poffCabinet = offSelfTestSection + sizeof(SelfTestSection);
  519. *pcbCabinet = SelfTestSection.cbCabFile;
  520. result = SELFTEST_NO_ERROR;
  521. }
  522. #endif
  523. #endif // CHECK_SECTION
  524. done:
  525. CloseHandle(hFile);
  526. done_no_exe:
  527. #ifdef ADD_SECTION
  528. CloseHandle(hCABFile);
  529. done_no_cab:
  530. #endif
  531. GlobalFree((HGLOBAL) pBuffer);
  532. done_no_buffer:
  533. #ifdef ADD_SECTION
  534. /* destroy failed attempt */
  535. if (result != SELFTEST_NO_ERROR)
  536. {
  537. DeleteFile(pszEXEFileName);
  538. }
  539. #endif
  540. return(result);
  541. }