NO

Author Topic: Generating CheckSum for AMD64  (Read 5775 times)

PabloMack

  • Guest
Generating CheckSum for AMD64
« 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.

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2091
Re: Generating CheckSum for AMD64
« Reply #1 on: May 01, 2019, 04:49:27 PM »
See An Analysis of the Windows PE Checksum Algorithm

EDIT: MS old ChkSum function:
Code: [Select]
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:
Code: [Select]
USHORT ChkSum1(ULONG ulPartialSum, PUSHORT pSource, ULONG nLength)
{
do
{
if ((nLength))
ulPartialSum += *pSource++;
ulPartialSum = (ulPartialSum >> 16) + (ulPartialSum & 0xffff);
} while (nLength--);
return (USHORT)ulPartialSum;
}
« Last Edit: May 02, 2019, 02:18:08 PM by TimoVJL »
May the source be with you

PabloMack

  • Guest
Re: Generating CheckSum for AMD64
« Reply #2 on: May 01, 2019, 06:57:38 PM »
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.
« Last Edit: May 01, 2019, 07:06:14 PM by PabloMack »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Generating CheckSum for AMD64
« Reply #3 on: May 01, 2019, 08:32:55 PM »
Start reading the imaghelp.h functions reference on msdn.
Then read carefully MapFileAndCheckSum() and 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.
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

PabloMack

  • Guest
Re: Generating CheckSum for AMD64
« Reply #4 on: May 02, 2019, 10:49:38 PM »
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.
« Last Edit: May 02, 2019, 10:54:54 PM by PabloMack »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Generating CheckSum for AMD64
« Reply #5 on: May 03, 2019, 12:38:48 PM »
Sample code:

Code: [Select]
#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.
« Last Edit: May 03, 2019, 12:47:18 PM by frankie »
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

PabloMack

  • Guest
Re: Generating CheckSum for AMD64
« Reply #6 on: May 03, 2019, 04:16:10 PM »
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.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Generating CheckSum for AMD64
« Reply #7 on: May 03, 2019, 05:20:18 PM »
Compile as console, and don't forget to enable MS extensions (/Ze switch from command line).  ;)
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

PabloMack

  • Guest
Re: Generating CheckSum for AMD64
« Reply #8 on: May 07, 2019, 08:51:31 PM »
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.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Generating CheckSum for AMD64
« Reply #9 on: May 08, 2019, 10:22:17 AM »
Enable debug also in linker tab.
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

PabloMack

  • Guest
Re: Generating CheckSum for AMD64
« Reply #10 on: May 09, 2019, 05:26:05 PM »
That fixed it. Thanks!