Pelles C forum
C language => Expert questions => Topic started by: PabloMack on May 01, 2019, 02:52:16 PM
-
I have written a working assembler and library manager targeting AMD64. I am currently writing a linker. The PE specification I am using says the following for the CheckSum field that is in the Optional Header that makes up part of the target EXE file:
"The image file checksum. The algorithm for computing the checksum is incorporated into IMAGHELP.DLL. The following are checked for validation at load time: all drivers, any DLL loaded at boot time, and any DLL that is loaded into a critical Windows process."
I noticed that there is a file called PellesC/Lib/Win64/imagehlp.lib in the Pelles C installation. Is this library capable of doing this function? If so, how would it be used?
Thanks.
-
See An Analysis of the Windows PE Checksum Algorithm (https://www.codeproject.com/Articles/19326/An-Analysis-of-the-Windows-PE-Checksum-Algorithm)
EDIT: MS old ChkSum function (http://bytepointer.com/resources/microsoft_pe_checksum_algo_distilled.htm):USHORT ChkSum(ULONG PartialSum, PUSHORT Source, ULONG Length)
{
while (Length--)
{
PartialSum += *Source++;
PartialSum = (PartialSum >> 16) + (PartialSum & 0xffff);
}
return (USHORT)(((PartialSum >> 16) + PartialSum) & 0xffff);
}
Length is ( filesize / 2 ).
To help optimizer:
USHORT ChkSum1(ULONG ulPartialSum, PUSHORT pSource, ULONG nLength)
{
do
{
if ((nLength))
ulPartialSum += *pSource++;
ulPartialSum = (ulPartialSum >> 16) + (ulPartialSum & 0xffff);
} while (nLength--);
return (USHORT)ulPartialSum;
}
-
Interesting. The PEChecksum.exe program might be able to assist. But it would be a manual operation which will require me to run the windowed program every time I do a new build. The article says that the book "The Art Of Computer Virus Research And Defense" contains the complete algorithm but it costs $36 on Amazon. It seems that may be the only way I am going to make the my linker able to generate an EXE without having to do that extra manual step.
The source code for PECheckSum is C++ (not C) so it can't be used with Pelles C. Perhaps it can be used with the OpenWatcom tool chain that I've been using since it also supports C++ but it is only 32-bit so I don't know if it cold work on 64-bit executables. My linker is written in C (not C++) so I'm not sure what I want to do. The source code only shows how to call the DLL which is where all the action happens.
-
Start reading the imaghelp.h functions reference on msdn (https://docs.microsoft.com/en-us/windows/desktop/debug/imagehlp-functions).
Then read carefully MapFileAndCheckSum() (https://docs.microsoft.com/en-us/windows/desktop/api/Imagehlp/nf-imagehlp-mapfileandchecksuma) and CheckSumMappedFile (https://docs.microsoft.com/en-us/windows/desktop/api/Imagehlp/nf-imagehlp-checksummappedfile).
You may prefer the second, so after mapping your exe, and after got the chechsum through CheckSumMappedFile(), you can patch it adding the Checksum.
-
The following web page seems to explain the algorithm while the link above
just talks about using some test programs.
http://bytepointer.com/resources/microsoft_pe_checksum_algo_distilled.htm
I see above that TimoVJL edited his post and it shows similar information .
But the complete algorithm seems to add the length after the partial is done.
Thanks to you both.
-
Sample code:
#include <windows.h>
#include <imagehlp.h>
#pragma comment(linker, "imagehlp.lib")
#include <stdio.h>
int main(int argc, char *argv[])
{
HANDLE FileHandle, MappingHandle;
LPVOID BaseAddress;
DWORD FileLength;
DWORD CheckSum;
DWORD HeaderSum;
PIMAGE_NT_HEADERS pNThdr;
// Open the file for read access
FileHandle = CreateFileW(L"file_to_check.exe", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "Error opening file!\n");
return 1;
}
// Create a file mapping
MappingHandle = CreateFileMapping(FileHandle, NULL, PAGE_READWRITE, 0, 0, NULL);
if (!MappingHandle)
{
fprintf(stderr, "Error mapping file!\n");
CloseHandle(FileHandle);
return 1;
}
// Map a view of the file
BaseAddress = MapViewOfFile(MappingHandle, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 0);
if (BaseAddress == NULL)
{
fprintf(stderr, "Error mapping view of file!\n");
CloseHandle(MappingHandle);
CloseHandle(FileHandle);
return 1;
}
// Get the length of the file in bytes and call ImageHlp function
FileLength = GetFileSize(FileHandle, NULL);
pNThdr = CheckSumMappedFile(BaseAddress, FileLength, &HeaderSum, &CheckSum);
int res;
if (!pNThdr)
{
//Function failed
fprintf(stderr, "Error checking file! Maybe the file isn't an executable.\n");
res = 1; //error
}
else
{
res = 0; //OK
if (HeaderSum)
{
//File has already a checksum.
//Check for correctness, print report and exit.
if (HeaderSum != CheckSum)
printf("File checksum exist and is wrong.\n"
"Value = 0x%08x, should be 0x%08x.\n", HeaderSum, CheckSum);
else
printf("File checksum exist and is OK. Value = 0x%08x.\n", HeaderSum);
}
else
{
//Set checksum
printf("Setting file checksum to value = 0x%08x.\n", CheckSum);
pNThdr->OptionalHeader.CheckSum = CheckSum;
}
}
// Cleanup and exit
UnmapViewOfFile(BaseAddress);
CloseHandle(MappingHandle);
CloseHandle(FileHandle);
return res;
}
I discourage the use of hand brew checksum code, because in case of changes made by MS it could go wrong.
It's always preferable to use the OS provided functions.
-
Thanks Frankie.
If I build this as a console program, I get the following failure:
Building main.obj.
C:\Program Files\PellesC\Include\Win\winnt.h(105): fatal error #1014: #error: "No Target Architecture".
*** Error code: 1 ***
Done.
If I build this as a Windows64 program, I get the following failure:
Building PE_ChkSum.obj.
Building PE_ChkSum.exe.
POLINK: error: Unresolved external symbol 'WinMain' - referenced from 'crt64.lib(_wincrt0.obj)'.
POLINK: fatal error: 1 unresolved external(s).
*** Error code: 1 ***
Done.
-
Compile as console, and don't forget to enable MS extensions (/Ze switch from command line). ;)
-
Okay. I checked MS extensions and now it builds with no errors. I also checked Full Debug
and selected X64 for a target and rebuilt but when I press F5 to debug, I get the message:
The file 'FileName.exe" cointains no debugging information! Do you want to continue?
If I continue I only get assembly. I've successfully used the debugger before and I don't
know what I am now doing wrong.
-
Enable debug also in linker tab.
-
That fixed it. Thanks!