Page 1 of 1

Modifying Manifests stored in exe results in cannot run.

Posted: Sat Dec 01, 2012 12:40 pm
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 ;}


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

Posted: Sat Dec 01, 2012 10:42 pm
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?

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

Posted: Sun Dec 02, 2012 2:06 am
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

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

Posted: Sun Dec 02, 2012 5:25 am
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)?

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

Posted: Sun Dec 02, 2012 2:37 pm
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.

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

Posted: Sun Dec 02, 2012 3:31 pm
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.

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

Posted: Wed Jan 23, 2013 12:22 pm
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.

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

Posted: Wed Jan 23, 2013 9:48 pm
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
  }
}

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

Posted: Wed Jan 23, 2013 10:00 pm
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>