Source code of Windows XP (NT5)
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.

507 lines
11 KiB

  1. //// DelCert - Delete all certificates in Win32 image
  2. //
  3. ///// delCert Command line
  4. //
  5. //c delCert Executable
  6. //
  7. //p Executable: Win32 binary to update
  8. //
  9. #pragma warning( disable : 4786 ) // map creates some ridiculously long debug identifiers
  10. #include "stdio.h"
  11. #include "windows.h"
  12. #include "imagehlp.h"
  13. #include "time.h"
  14. #define DBG 1
  15. void __cdecl DebugMsg(char *fmt, ...) {
  16. va_list vargs;
  17. va_start(vargs, fmt);
  18. vfprintf(stderr, fmt, vargs);
  19. }
  20. BOOL g_fError = FALSE;
  21. #define warn DebugMsg
  22. #define MUST(a,b) {HRESULT hr; hr = (a); if (hr!= S_OK) {if (!g_fError) DebugMsg b; g_fError = TRUE; return E_FAIL;};}
  23. #define SHOULD(a,b) {HRESULT hr; hr = (a); if (hr!= S_OK) {DebugMsg b; g_fWarn = TRUE; return S_FALSE;};}
  24. #if DBG
  25. #pragma message("Checked build")
  26. #define OK(a) {HRESULT hr; hr = (a); if (hr!= S_OK) {DebugMsg("%s(%d): error RSRC999 : HRESULT not S_OK: "#a"\n", __FILE__, __LINE__); return hr;};}
  27. #define ASSERT(a) {if (!(a)) {DebugMsg("%s(%d): error RSRC999 : Assertion failed: "#a"\n", __FILE__, __LINE__); return E_UNEXPECTED;};}
  28. #else
  29. #pragma message ("Free build")
  30. #define OK(a) {HRESULT hr; hr = (a); if (hr != S_OK) return hr;}
  31. #define ASSERT(a) {if (!(a)) {return E_UNEXPECTED;};}
  32. #endif
  33. //// Mapped files
  34. //
  35. // File mapping is used to read executable and token files.
  36. //
  37. // File mapping is also used to update in place checksum information
  38. // in executable and symbol files.
  39. class MappedFile {
  40. HANDLE m_hFileMapping;
  41. BOOL fRW; // True when writeable
  42. char m_szFileName[MAX_PATH];
  43. public:
  44. BYTE *m_pStart;
  45. BYTE *m_pLimit;
  46. MappedFile() {m_hFileMapping = NULL;}
  47. HRESULT Open(const char *pcFileName, BOOL fWrite) {
  48. HANDLE hFile;
  49. strcpy(m_szFileName, pcFileName);
  50. hFile = CreateFileA(
  51. pcFileName,
  52. GENERIC_READ | (fWrite ? GENERIC_WRITE : 0),
  53. FILE_SHARE_READ | (fWrite ? FILE_SHARE_WRITE | FILE_SHARE_DELETE : 0 ),
  54. NULL,
  55. OPEN_EXISTING,
  56. FILE_ATTRIBUTE_NORMAL,
  57. NULL);
  58. ASSERT(hFile != INVALID_HANDLE_VALUE);
  59. m_hFileMapping = CreateFileMapping(
  60. hFile,
  61. NULL,
  62. fWrite ? PAGE_READWRITE : PAGE_WRITECOPY,
  63. 0,0, NULL);
  64. ASSERT(m_hFileMapping != NULL);
  65. m_pStart = (BYTE*) MapViewOfFile(
  66. m_hFileMapping,
  67. fWrite ? FILE_MAP_WRITE : FILE_MAP_READ,
  68. 0,0, 0);
  69. ASSERT(m_pStart != NULL);
  70. m_pLimit = m_pStart + GetFileSize(hFile, NULL);
  71. CloseHandle(hFile);
  72. fRW = fWrite;
  73. return S_OK;
  74. }
  75. DWORD CalcChecksum() {
  76. DWORD dwHeaderSum;
  77. DWORD dwCheckSum;
  78. if (CheckSumMappedFile((void*)m_pStart, (DWORD)(m_pLimit-m_pStart), &dwHeaderSum, &dwCheckSum) == NULL) {
  79. return 0;
  80. } else {
  81. return dwCheckSum;
  82. }
  83. }
  84. HRESULT Close() {
  85. if (m_pStart) {
  86. UnmapViewOfFile(m_pStart);
  87. CloseHandle(m_hFileMapping);
  88. m_hFileMapping = NULL;
  89. m_pStart = NULL;
  90. }
  91. return S_OK;
  92. }
  93. };
  94. class Win32Executable : public MappedFile {
  95. IMAGE_NT_HEADERS *m_pNtHeader;
  96. IMAGE_SECTION_HEADER *m_pSections;
  97. public:
  98. DWORD GetChecksum() const {return m_pNtHeader->OptionalHeader.CheckSum;}
  99. void SetChecksum(DWORD dwChecksum) {m_pNtHeader->OptionalHeader.CheckSum=dwChecksum;}
  100. void SetCertificateRVA (DWORD rva)
  101. {
  102. m_pNtHeader->OptionalHeader
  103. .DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]
  104. .VirtualAddress
  105. = rva;
  106. }
  107. HRESULT Open(const char *pcFileName, BOOL fWrite) {
  108. int i;
  109. OK(MappedFile::Open(pcFileName, fWrite));
  110. MUST(( *(WORD*)m_pStart == IMAGE_DOS_SIGNATURE
  111. && *(WORD*)(m_pStart+0x18) >= 0x40) // WinVer >= 4
  112. ? S_OK : E_FAIL,
  113. ("RSRC : error RSRC501: %s is not an executable file\n", pcFileName));
  114. m_pNtHeader = (IMAGE_NT_HEADERS*)(m_pStart + *(WORD*)(m_pStart+0x3c));
  115. MUST((m_pNtHeader->Signature == IMAGE_NT_SIGNATURE)
  116. ? S_OK : E_FAIL,
  117. ("RSRC : error RSRC502: %s is not a Win32 executable file\n", pcFileName));
  118. m_pSections = (IMAGE_SECTION_HEADER*)(m_pNtHeader+1);
  119. return S_OK;
  120. }
  121. };
  122. void DeleteCertificates(
  123. const char *fileName
  124. )
  125. {
  126. HANDLE fileHandle = CreateFile(
  127. fileName,
  128. GENERIC_READ | GENERIC_WRITE,
  129. 0,
  130. NULL,
  131. OPEN_EXISTING,
  132. 0,
  133. NULL
  134. );
  135. if (fileHandle == INVALID_HANDLE_VALUE) {
  136. warn("Could not access %s\n", fileName);
  137. return;
  138. }
  139. DWORD certificateCount;
  140. DWORD *certificateIndices;
  141. if (!ImageEnumerateCertificates(
  142. fileHandle,
  143. CERT_SECTION_TYPE_ANY,
  144. &certificateCount,
  145. NULL,
  146. 0
  147. )) {
  148. warn("Could not enumerate certificates in %s.\n", fileName);
  149. CloseHandle(fileHandle);
  150. return;
  151. }
  152. if (certificateCount == 0) {
  153. warn("No certificates found in %s.\n", fileName);
  154. CloseHandle(fileHandle);
  155. return;
  156. }
  157. certificateIndices = new DWORD[certificateCount];
  158. if (certificateIndices == NULL) {
  159. CloseHandle(fileHandle);
  160. warn("Couldn't allocate buffer for %d certificate indices for %s.\n", certificateCount, fileName);
  161. return;
  162. }
  163. ImageEnumerateCertificates(
  164. fileHandle,
  165. CERT_SECTION_TYPE_ANY,
  166. &certificateCount,
  167. certificateIndices,
  168. certificateCount
  169. );
  170. if (certificateCount == 0) {
  171. warn("Couldn't get certificate indices for %s.\n", fileName);
  172. CloseHandle(fileHandle);
  173. return;
  174. }
  175. for (DWORD i=0; i<certificateCount; i++) {
  176. if (!ImageRemoveCertificate(fileHandle, certificateIndices[i])) {
  177. warn("Could not remove certificate index %d from %s\n", certificateIndices[i], fileName);
  178. CloseHandle(fileHandle);
  179. return;
  180. }
  181. }
  182. warn("All %d certificate(s) removed from %s.\n", certificateCount, fileName);
  183. CloseHandle(fileHandle);
  184. // Now clear the rva of any security certificates
  185. Win32Executable w32x;
  186. if (w32x.Open(fileName, TRUE) != S_OK) {
  187. warn("Could not map %s to update security certificate RVA\n", fileName);
  188. return;
  189. }
  190. w32x.SetCertificateRVA(0);
  191. w32x.SetChecksum(w32x.CalcChecksum());
  192. w32x.Close();
  193. warn("Certificate section virtual address zeroed in %s section index.\n", fileName);
  194. }
  195. //// Parameter parsing
  196. //
  197. //
  198. char g_cSwitch = '-'; // Switch character is recorded the first time one is seen
  199. void SkipWhitespace(char** p, char* pE) {
  200. while ((*p<pE) && ((**p==' ')||(**p==9))) (*p)++;
  201. }
  202. void ParseToken(char** p, char* pE, char* s, int l) {
  203. // Parse up to whitespace into string s
  204. // Guarantee zero terminator and modify no more than l chars
  205. // Return with p beyond whitespace
  206. if (*p < pE && **p == '\"') {
  207. // Quoted parameter
  208. (*p)++; // Skip over leading quote
  209. while (l>0 && *p<pE && **p!='\"') {
  210. *s=**p; s++; (*p)++; l--;
  211. }
  212. // Skip any part of token that didn't fit s
  213. while (*p<pE && **p!='\"') { // Skip up to terminating quote
  214. (*p)++;
  215. }
  216. if (*p<pE) { // Skip over terminating quote
  217. (*p)++;
  218. }
  219. } else {
  220. // Unquoted parameter
  221. while ((l>0) && (*p<pE) && (**p>' ')) {
  222. *s=**p; s++; (*p)++;
  223. l--;
  224. }
  225. // Skip any part of token that didn't fit into s
  226. while ((*p<pE) && (**p>' ')) (*p)++;
  227. }
  228. if (l>0)
  229. *s++ = 0;
  230. else
  231. *(s-1) = 0;
  232. SkipWhitespace(p, pE);
  233. }
  234. void ParseName(char** p, char* pE, char* s, int l) {
  235. // Uses ParseToken to parse a name such as a filename.
  236. // If the name starts with '/' or '-' it is assumed to be
  237. // an option rather than a filename and ParseName returns
  238. // a zero length string.
  239. if (*p<pE && **p==g_cSwitch) {
  240. // This is an option and should not be treated as a name argument
  241. s[0] = 0;
  242. } else {
  243. ParseToken(p, pE, s, l);
  244. }
  245. }
  246. void DisplayUsage() {
  247. fprintf(stdout, "Usage: delCert executable\n");
  248. }
  249. DWORD g_dwOptions = 0;
  250. #define OPTHELP 1
  251. HRESULT ProcessParameters() {
  252. char *p; // Current command line character
  253. char *pE; // End of command line
  254. char *pcStop;
  255. char token [MAX_PATH];
  256. char szExecutable [MAX_PATH];
  257. int i,j;
  258. int cFiles = 0;
  259. BOOL fArgError = FALSE;
  260. p = GetCommandLine();
  261. pE = p+strlen((char *)p);
  262. // Skip command name
  263. ParseToken(&p, pE, token, sizeof(token));
  264. while (p<pE) {
  265. ParseToken(&p, pE, token, sizeof(token));
  266. if ( token[0] == '-'
  267. || token[0] == '/') {
  268. // Process command option(s)
  269. i = 1;
  270. g_cSwitch = token[0]; // Argument may start with the other switch character
  271. CharLower((char*)token);
  272. while (token[i]) {
  273. switch (token[i]) {
  274. case '?':
  275. case 'h': g_dwOptions |= OPTHELP; break;
  276. default:
  277. fprintf(stderr, "Unrecognised argument '%c'.\n", token[i]);
  278. fArgError = TRUE;
  279. break;
  280. }
  281. i++;
  282. }
  283. } else {
  284. // Process filename
  285. switch (cFiles) {
  286. case 0: strcpy(szExecutable, token); break;
  287. }
  288. cFiles++;
  289. }
  290. }
  291. if ( fArgError
  292. || g_dwOptions & OPTHELP) {
  293. DisplayUsage();
  294. return S_OK;
  295. } else if (cFiles != 1) {
  296. DisplayUsage();
  297. return E_INVALIDARG;
  298. } else {
  299. // We have valid parameters
  300. DeleteCertificates(szExecutable);
  301. return S_OK;
  302. }
  303. }
  304. int _cdecl main(void) {
  305. if (SUCCEEDED(ProcessParameters())) {
  306. return 0; // No problems
  307. } else {
  308. return 2; // Error(s)
  309. }
  310. }