c++winapicode-signingauthenticode

How to read altered certificate data using WinApi?


I have a simple program:

int main(){
    int t = 12 + 34;
    return t;
}

The executable of this program is signed and the sign data altered with this disitool utility as described in in this thread: Codesign an executable and allow the modification of some bytes with command:

python.exe disitool.py inject --paddata HelloWorld.exe id.txt HelloWorld_altered.exe

The contents of id.txt:

super_id=test9a0

If I understand it correctly this utility adds desired data into certificate section at the end of the file and recalulates hash of the sign. How can I read this added data from within my program, that is to read string super_id=test9a0.


Solution

  • The injected data is located after the Authenticode signature, which is located in the The Attribute Certificate Table of the file (PE Format). Here is some sample code to read it from the file:

    #include <windows.h>
    #include <wintrust.h>
    
    void ReadAuthenticodeTail(PCWSTR path, LPBYTE* tailData, LPDWORD tailSize)
    {
      *tailData = nullptr;
      *tailSize = 0;
    
      // open file & map it in memory
      auto file = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
      if (file != INVALID_HANDLE_VALUE)
      {
        auto mapping = CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
        if (mapping)
        {
          auto map = (LPBYTE)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
          if (map)
          {
            // do some checks
            auto dosHeader = (PIMAGE_DOS_HEADER)map;
            if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE)
            {
              auto headers = (PIMAGE_NT_HEADERS)(map + dosHeader->e_lfanew);
              if (headers->Signature == IMAGE_NT_SIGNATURE)
              {
                // get to Attribute Certificate Table
                auto va = headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
                auto size = headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
                if (va && size)
                {
                  // va is in fact a file offset
                  // cf https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-attribute-certificate-table-image-only
                  auto cert = (LPWIN_CERTIFICATE)(map + va);
    
                  // check it's authenticode signature and there's a tail
                  if (cert->wRevision == WIN_CERT_REVISION_2_0 &&
                    cert->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA &&
                    cert->dwLength < size)
                  {
                    // read what's after certificate (the tail)
                    *tailSize = size - cert->dwLength;
                    *tailData = new BYTE[*tailSize];
                    CopyMemory(*tailData, map + va + cert->dwLength, *tailSize);
                  }
                }
              }
            }
            UnmapViewOfFile(map);
          }
          CloseHandle(mapping);
        }
        CloseHandle(file);
      }
    }
    
    int main()
    {
      LPBYTE tail;
      DWORD size;
      ReadAuthenticodeTail(L"c:\\somepath\\SomeSignedFileWithInjectedData.exe", &tail, &size);
      if (tail)
      {
        // TODO: do something with it...
    
        delete[] tail;
      }
      return 0;
    }