Modifying Manifests stored in exe results in cannot run.

Windows specific forum
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Modifying Manifests stored in exe results in cannot run.

Post by jassing »

I was hoping to automate 'fixing' the manifest. (author, product,version,etc)

(Ideally I think we should be able to use a myprogram.exe.manifest that is auto-imported, or at the very least, populate it with information from the "Compiler Options->Version Info")

I have some simple code that works in updating the manifest, but the resulting exe yields an error:
"The system cannot execute the specified program."

Doing a byte-by-byte compare, the only differences between the 'original' and the 'modified' is the xml for the manifest. filesize remains unchanged.

Is there a magic byte or two in the exe that specifies a validation of the manifest?

I have tried keeping the file the same size and also keeping the same # of 'nulls' at the end of the file. Either way, the resulting file cannot be executed, so there must be something telling the os that the manifest isn't right...

FWIW, here's the code i'm using:
test Exe:

Code: Select all

MessageRequester("Test","Test")

; IDE Options = PureBasic 5.00 (Windows - x86)
; CursorPosition = 1
; EnableUser
; Executable = manifestHackTest.exe
; DisableDebugger
; IncludeVersionInfo
; VersionField0 = 1,2,3,4
; VersionField1 = 1,2,3,5
; VersionField2 = Test Company
; VersionField3 = Product Name
; VersionField4 = 1.2.3.6
; VersionField5 = 1.2.3.7
; VersionField6 = 1.2.3.8
; VersionField15 = VOS_NT_WINDOWS32
; VersionField16 = VFT_APP
Code to read/modify/save the manifest w/in the exe (This isn't great code, it was just test code to see it can be done...)

Code: Select all

;- Setting
;{
Enumeration ; file Operation mode
  #KeepFileSameSize
  #KeepTrailingNullsConsistient
EndEnumeration

#testing = #True
#mode = #KeepTrailingNullsConsistient
;#mode = #KeepFileSameSize

EnableExplicit ;}

Procedure ModifyManfiest( cFile.s, cNewAuthorInfo.s, cNewVersion.s )
	Protected nStart, nEnd, nLen, nWritten, i
	Protected fh, hXML, *mem, *xml
  Protected bSuccess = #False
  CompilerIf #mode = #KeepTrailingNullsConsistient
    Protected nEndNullCount
  CompilerEndIf
  
  ;- Read file
  fh = OpenFile(#PB_Any, cFile) ;{
  If fh
    *mem = AllocateMemory(Lof(fh)) ;{
    If *mem 
      If ReadData(fh, *mem, Lof(fh)) = Lof(fh) ;{
        ;- Find the xml code
        For i = Lof(fh)-10 To 0 Step -1 ;{
          If PeekS(*mem+i, 11) = "</assembly>" 
            nEnd = *mem+i+11
          ElseIf PeekS(*mem+i, 10) = "<assembly "
            nStart = *mem+i
            FileSeek(fh, i) ; Reset file pointer to start of xml
            Break
          EndIf
        Next ;}
        
        Debug "original XML Length: "+Str(nEnd-nStart)
        ;Debug "XML: "+PeekS(nStart, nEnd-nStart)
        
        CompilerIf #mode = #KeepTrailingNullsConsistient
          ; Count the nulls, only needed if we're keeping the same null count of the new file--this way either shortens or grows the exe
          For i = *mem+Lof(fh) To *mem Step -1  ;{
            If PeekB( i-1 ) = 0
              nEndNullCount+1
            Else : Break;
            EndIf
          Next ;}
          Debug "End Null Count: "+Str(nEndNullCount)
        CompilerEndIf
        
        ;- Work with the xml
        hXML = CatchXML(#PB_Any, nStart, nEnd-nStart)  ;{
        If hXML
          *xml = MainXMLNode(hXML)
          *xml = XMLNodeFromPath(*xml, "/assembly/assemblyIdentity")
          ; Set the new values we want to use.
          SetXMLAttribute(*xml, "name", cNewAuthorInfo)
          SetXMLAttribute(*xml, "version", cNewVersion)
          
          ;- Save the xml to memory
          nLen = ExportXMLSize(hXML, #PB_XML_NoDeclaration) ;{
          Debug "New XML Length: "+Str(nLen     )
          If ExportXML(hXML, nStart, nLen, #PB_XML_NoDeclaration)
            
            ; Close out the xml stuff.
            FreeXML(hXML)
            
            ;- Write the new manifest to the fle
            For i = 0 To nLen  ;{
              ; this 1st case is only trying to keep the xml output similar.
              If PeekS(nStart+i, Len("<description/>"))="<description/>" 
                i+Len("<description/>")
                WriteString(fh, "<description></description>")
                nWritten + Len("<description></description>")
                
              ElseIf PeekB(nStart+i)<>$0D ; the xml didn't have any $0d (Linefeed), so write any bytes that are not $0d
                nWritten+1
                WriteByte(fh, PeekB(nStart+i))
              EndIf
            Next  ;}
            
            ;- Now either pad the same # of nulls or keep the file the same length...
            CompilerSelect #mode
            CompilerCase #KeepFileSameSize ; Pad file With nulls To original file length.
            	Debug "Keeping the file the same size"  ;{
	            While Loc(fh)<Lof(fh)
	              WriteByte(fh, 0)
	            Wend ;}
	            
	          CompilerCase #KeepTrailingNullsConsistient ; pad file with the same # of nulls the original file had.
	          	Debug "Padding file with nulls (truncate or grow file as needed)" ;{
	            For i = 1 To nEndNullCount
	              WriteByte(fh, 0)
	            Next
	            TruncateFile(fh) ;}
	            
        		CompilerEndSelect
        
        		bSuccess=#True
          Else : Debug "Failed to Export XML"
          EndIf ;}
        Else : Debug "Failed to Catch XML"
        EndIf ;}
      Else : Debug "Failed to read complete file"
      EndIf ;}
      FreeMemory(*mem)
    Else : Debug "Failed to allocate memory"
    EndIf ;}
    CloseFile(fh)
  Else : Debug "Failed to open file"
  EndIf ;}
  
  ProcedureReturn bSuccess
EndProcedure

CompilerIf #testing  ;{
	If FileSize("manifestHackTest.exe") < 0
		Debug "Please build the hack test program 1st"
	EndIf 
	
	If FileSize("manifestHackTest.exe-org") = -1
		Debug "Creating back/original"
		CopyFile("manifestHackTest.exe","manifestHackTest.exe-org")
	Else : Debug "Restoring original"
		CopyFile("manifestHackTest.exe-org","manifestHackTest.exe")
	EndIf 
	
	If ModifyManfiest("manifestHackTest.exe","New Author.New Company.New Product", "1.2.3.4")
		Debug "Modified OK"
	Else : Debug "Failed to modify"
	EndIf
CompilerEndIf ;}

User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Modifying Manifests stored in exe results in cannot run.

Post by Danilo »

@jassing:
Did you try to disable XP skins support (so PB's manifest is not included), and then add a resource file (could be auto generated by a tool)
with your own manifest?
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: Modifying Manifests stored in exe results in cannot run.

Post by jassing »

Danilo wrote:@jassing:
Did you try to disable XP skins support (so PB's manifest is not included), and then add a resource file (could be auto generated by a tool)
with your own manifest?
Honestly, I hadn't even thought to try that -- but that is certainly a much simpler approach.
Thanks.

I wasn't aware that the skin support was what was triggering it...

Still, would be nice if it were more customizable "built in" - but my own rc file is a fine way to go.

-j
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Modifying Manifests stored in exe results in cannot run.

Post by Danilo »

jassing wrote:Still, would be nice if it were more customizable "built in"
A feature request to add an option to specify your own manifest file? And if it is a project
with your own manifest, add the manifest to the project (like VisualStudio)?
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: Modifying Manifests stored in exe results in cannot run.

Post by jassing »

Danilo wrote:
jassing wrote:Still, would be nice if it were more customizable "built in"
A feature request to add an option to specify your own manifest file? And if it is a project
with your own manifest, add the manifest to the project (like VisualStudio)?
Right -- it could grab some of the information from the Version Info tab... Right now, it seems that the 'built in' manifest was an afterthought and then forgotten.
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: Modifying Manifests stored in exe results in cannot run.

Post by jassing »

Danilo wrote:@jassing:
Did you try to disable XP skins support (so PB's manifest is not included), and then add a resource file (could be auto generated by a tool)
with your own manifest?
On all my projects, "Enable XP Skin Support" is not checked.
Thorium
Addict
Addict
Posts: 1308
Joined: Sat Aug 15, 2009 6:59 pm

Re: Modifying Manifests stored in exe results in cannot run.

Post by Thorium »

If the manifest is stored as a ressource you can change it with this function: http://msdn.microsoft.com/en-us/library ... 85%29.aspx

I guess your problem is you are changing the size of the XML but not updating the size in the ressource table.
EXE File size and count of zeros at the end do not matter. The zeros at the end are just for padding, you can overwrite them. The important part is to keep integrity. If you change the ressource size you need to update it in the ressource table. If after your changed ressource are more ressources the pointers to them need to be updated, etc.
Just use the WinAPI function, it will take care of all that.
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Modifying Manifests stored in exe results in cannot run.

Post by Josh »

jassing wrote:I was hoping to automate 'fixing' the manifest. (author, product,version,etc)
I use my own created resourcefile to set version, company etc. I use a resourcefile like the following template and have embedded it in my exe. This resourcefile can be created easily automatic.

Code: Select all

1 VERSIONINFO
FILEVERSION 0,0,0,0
PRODUCTVERSION 0,0,0,0
FILEOS VOS_UNKNOWN
FILETYPE VFT_UNKNOWN
{
  BLOCK "StringFileInfo"
  {
    BLOCK "040704b0"
    {
      VALUE "CompanyName"     , "\0"
      VALUE "ProductName"     , "\0"
      VALUE "ProductVersion"  , "00.01.B01\0"
      VALUE "FileVersion"     , "\0"
      VALUE "FileDescription" , "\0"
      VALUE "InternalName"    , "\0"
      VALUE "OriginalFilename", "\0"
      VALUE "LegalCopyright"  , "\0"
      VALUE "LegalTrademarks" , "\0"
      VALUE "PrivateBuild"    , "\0"
      VALUE "SpecialBuild"    , "Testversion\0"
      VALUE "Email"           , "office@notimplemented.com\0"
      VALUE "Website"         , "www.notimplemented.com\0"
      VALUE "Frei1"           , "\0"
      VALUE "Frei2"           , "\0"
      VALUE "Frei3"           , "\0"
    }
  }
  BLOCK "VarFileInfo"
  {
    VALUE "Translation", 0x0407, 0x4b0
  }
}
sorry for my bad english
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Modifying Manifests stored in exe results in cannot run.

Post by ts-soft »

@Josh
You shows the versionsinfo, not the manifest!
Manifest looks like:

Code: Select all

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    version="1.0.0.0"
    processorArchitecture="amd64"
    name="CompanyName.ProductName.YourApp"
    type="win32" />
  <description></description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="amd64"
        publicKeyToken="6595b64144ccf1df"
        language="*" />
    </dependentAssembly>
  </dependency>
	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
        </requestedPrivileges>
       </security>
  </trustInfo>

</assembly>
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
Post Reply