Solved

Modify resource of binary

Posted on 2002-04-25
7
317 Views
Last Modified: 2013-12-03
Hi,
I want to programatically update the resource of a binary (esp. the version resource).

a) I know there's an API way to do this in W2K (and NT4 I guess). Anybody knows of a sample, or a howto?

b) Is there a "dirty" way to do this on Win9x, too? I'm looking for either a short, or an easy-to-reuse version - I don#t want to write a PE parser.. (50 pts extra)


Thanks
Peter
0
Comment
Question by:peterchen092700
  • 3
  • 2
  • 2
7 Comments
 
LVL 22

Expert Comment

by:cookre
ID: 6968721
I've never heard of anything to re-create a version resource with differing length, but overwriting the existing block is certainly legitimate.

Here's something I wrote several years ago.

You can ignore the chunk near the front that deals with NLMs (this was itself part of an NLM library for Rexxware on NetWare servers).

Now, all this did was fetch version info, but, if you can fetch it, you can change it.

(If nothing else, at least the location in .rsrc of the offset to VS_VERSION_INFO may be of some value).





LONG GetFileVer(char     * Name
               ,LONG       Argc
               ,RXSTRING   Argv[]
               ,char     * QueueName
               ,RXSTRING * RetStr)
{
char          FullFileName[256]; // Just a local copy of the arg file
char          RetMsg[256];       // Place to plop our return into
unsigned char RSRCBuf[1024];     // Buffer for the first 1K of the file (look for .rsrc)
int           FileHan;           // File handle for subject file
long          BytesRead;         // Return from 'read'
long          SearchOffset;      // This is were in the arg file we start the search for VS_VERSION
int           UniCodeFlag;       // 1=Not Unicode, 2=Unicode
int           i;                 // Hmm.
long          il;                // Hmmmm
long          FileSize;          // Size of target file in bytes
long          BuffSize;          // Space needed to hold portion of file from SearchOffset to the end
void        * ReadBuff;          // Where we load the tail end of the file into
long          IOStat;            // Result for lseek, read, et al
int           FoundVS;           // Result of search for VS_VERSION_INFO
char          FoundFV[256];      // File version we found
LONG          NLMSubVer1;
LONG          NLMSubVer2;
LONG          NLMSubVer3;
char          SubVerStr1[256];
char          SubVerStr2[256];

logit("GetFileVer referrenced");
// Let main know that something is going on
TimesCalled+=1;

// Save arg file name
strcpy(FullFileName,Argv[0].strptr);
logit(FullFileName);

// Filter out names we can't do anything with
if (strlen(FullFileName)<5)
   {
   strcpy(RetMsg,"%1%,%Invalid file name%");
   goto DoReturn;
   }
// Filter out extensions we don't care about
if ( (0!=stricmp(&FullFileName[strlen(FullFileName)-4],".dll"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".exe"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".vxd"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".drv"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".386"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".cpl"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".nlm"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".oca"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".ocx"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".olb"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".qtc"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".tlb"))
   &&(0!=stricmp(&FullFileName[strlen(FullFileName)-4],".trn")))
   {
   strcpy(RetMsg,"%2%,%Version info not available for this extension%");
   goto DoReturn;
   }


/* Let's get NLMs out of the way first */
if (0==stricmp(&FullFileName[strlen(FullFileName)-4],".nlm"))
   {
   /* Why, you may ask, do we not use ReturnNLMVersionInfoFromFile to get version info? */
   /* Well, for two reasons.  First, that call sometimes fails for loaded NLMs.         */
   /* Second, for some reason I have yet to determine, our method gets version info     */
   /* for some NLMs on which the API call fails.  So there.  bphbhphppp.                */
   FileHan=open(FullFileName,O_RDONLY|O_BINARY);
   if (FileHan==-1)
      {
      strcpy(RetMsg,"%100%,%Unable to open file%");
      goto DoReturn;
      }
   // Load up the first 1K to look in for 'VeRsIoN#'
   BytesRead=read(FileHan,RSRCBuf,1024);
   if (BytesRead<0)
      {
      strcpy(RetMsg,"%101%,%I/O error reading file%");
      goto DoReturn;
      }
   SearchOffset=0;
   // OK, OK, do the search awready
   for (i=0; i<1020; i++)
       {
       if (RSRCBuf[i+0]!='V') continue;
       if (RSRCBuf[i+1]!='e') continue;
       if (RSRCBuf[i+2]!='R') continue;
       if (RSRCBuf[i+3]!='s') continue;
       if (RSRCBuf[i+4]!='I') continue;
       if (RSRCBuf[i+5]!='o') continue;
       if (RSRCBuf[i+6]!='N') continue;
       if (RSRCBuf[i+7]!='#') continue;
       // If we find .rsrc, then we know the VS_VERSION_INFO is Unicode,
       // and we can extract the offset into the file of where the version block is.
       NLMSubVer1=(RSRCBuf[i+11]<<24)
                 |(RSRCBuf[i+10]<<16)
                 |(RSRCBuf[i+9]<<8)
                 |(RSRCBuf[i+8]);
       NLMSubVer2=(RSRCBuf[i+15]<<24)
                 |(RSRCBuf[i+14]<<16)
                 |(RSRCBuf[i+13]<<8)
                 |(RSRCBuf[i+12]);
       NLMSubVer3=(RSRCBuf[i+19]<<24)
                 |(RSRCBuf[i+18]<<16)
                 |(RSRCBuf[i+17]<<8)
                 |(RSRCBuf[i+16]);
       SearchOffset=1;
       break;
       }
   if (SearchOffset==1)
      {
      sprintf(SubVerStr1,"%ld",NLMSubVer1);
      sprintf(SubVerStr2,"%ld",NLMSubVer2);
      strcpy(RetMsg,"%0%,%");
      strcat(RetMsg,SubVerStr1);
      strcat(RetMsg,".");
      strcat(RetMsg,SubVerStr2);
      if (NLMSubVer3!=0)
         {
         strcat(RetMsg," ");
         RetMsg[strlen(RetMsg)-1]=0x60+(short)NLMSubVer3;
         }
      strcat(RetMsg,"%");
      }
   else
      {
      strcpy(RetMsg,"%3%,%VS_VERSION_INFO not found%");
      }
   goto DoReturn;
   }

// OK, we want to look at this file
FileHan=open(FullFileName,O_RDONLY|O_BINARY);
if (FileHan==-1)
   {
   strcpy(RetMsg,"%100%,%Unable to open file%");
   goto DoReturn;
   }

// Load up the first 1K to look in for '.rsrc'
// The .rsrc block has a pointer to the VS_VERSION_INFO block.
// If .rsrc isn't there, we have to search the entire file for VS_VERSION_INFO.
BytesRead=read(FileHan,RSRCBuf,1024);
if (BytesRead<0)
   {
   strcpy(RetMsg,"%101%,%I/O error reading file%");
   goto DoReturn;
   }
SearchOffset=0;
UniCodeFlag=1;  // Say NO to Unicode

// OK, OK, do the search awready
for (i=0; i<1020; i++)
    {
    if (RSRCBuf[i]!='.') continue;
    if (RSRCBuf[i+1]!='r') continue;
    if (RSRCBuf[i+2]!='s') continue;
    if (RSRCBuf[i+3]!='r') continue;
    if (RSRCBuf[i+4]!='c') continue;
    // If we find .rsrc, then we know the VS_VERSION_INFO is Unicode,
    // and we can extract the offset into the file of where the version block is.
    UniCodeFlag=2;
    SearchOffset=(RSRCBuf[i+23]<<24)
                |(RSRCBuf[i+22]<<16)
                |(RSRCBuf[i+21]<<8)
                |(RSRCBuf[i+20]);
    break;
    }
// Now look for VS_VERSIONINFO in Unicode (or not)
// (The guys with no .rsrc with versions don't use UniCode)

// Get total file size
FileSize=lseek(FileHan,0l,SEEK_END);
if (FileSize<0)
   {
   strcpy(RetMsg,"%102%,%lseek error%");
   goto DoReturn;
   }
BuffSize=FileSize-SearchOffset;

// Get space to load last part of file into
ReadBuff=malloc(BuffSize);
if (ReadBuff==NULL)
   {
   strcpy(RetMsg,"%103%,%malloc error%");
   goto DoReturn;
   }

// Position file to search begin offset
IOStat=lseek(FileHan,SearchOffset,SEEK_SET);
if (IOStat<0)
   {
   strcpy(RetMsg,"%104%,%lseek2 error%");
   free(ReadBuff);
   goto DoReturn;
   }

// Load up the tail of the file
IOStat=read(FileHan,ReadBuff,BuffSize);
if (IOStat<0)
   {
   strcpy(RetMsg,"%105%,%read error%");
   free(ReadBuff);
   goto DoReturn;
   }

// Search for VS_VERSION_INFO string
FoundVS=0;
for (il=0; il<((long)(BuffSize-30)); il++)
    {
    if (*((char *)ReadBuff+il)!='V') continue;
    if (*((char *)ReadBuff+il+1*UniCodeFlag)!='S') continue;
    if (*((char *)ReadBuff+il+2*UniCodeFlag)!='_') continue;
    if (*((char *)ReadBuff+il+3*UniCodeFlag)!='V') continue;
    if (*((char *)ReadBuff+il+4*UniCodeFlag)!='E') continue;
    if (*((char *)ReadBuff+il+5*UniCodeFlag)!='R') continue;
    if (*((char *)ReadBuff+il+6*UniCodeFlag)!='S') continue;
    if (*((char *)ReadBuff+il+7*UniCodeFlag)!='I') continue;
    if (*((char *)ReadBuff+il+8*UniCodeFlag)!='O') continue;
    if (*((char *)ReadBuff+il+9*UniCodeFlag)!='N') continue;
    if (*((char *)ReadBuff+il+10*UniCodeFlag)!='_') continue;
    if (*((char *)ReadBuff+il+11*UniCodeFlag)!='I') continue;
    if (*((char *)ReadBuff+il+12*UniCodeFlag)!='N') continue;
    if (*((char *)ReadBuff+il+13*UniCodeFlag)!='F') continue;
    if (*((char *)ReadBuff+il+14*UniCodeFlag)!='O') continue;
    FoundVS=1;
    break;
    }
if (FoundVS==0)
   {
   strcpy(RetMsg,"%3%,%VS_VERSION_INFO not found%");
   free(ReadBuff);
   goto DoReturn;
   }

// Now look for FileVersion string
FoundFV[0]='\0';
for (il=il; il<((long)(BuffSize-30)); il++)
    {
    if (*((char *)ReadBuff+il)!='F') continue;
    if (*((char *)ReadBuff+il+1*UniCodeFlag)!='i') continue;
    if (*((char *)ReadBuff+il+2*UniCodeFlag)!='l') continue;
    if (*((char *)ReadBuff+il+3*UniCodeFlag)!='e') continue;
    if (*((char *)ReadBuff+il+4*UniCodeFlag)!='V') continue;
    if (*((char *)ReadBuff+il+5*UniCodeFlag)!='e') continue;
    if (*((char *)ReadBuff+il+6*UniCodeFlag)!='r') continue;
    if (*((char *)ReadBuff+il+7*UniCodeFlag)!='s') continue;
    if (*((char *)ReadBuff+il+8*UniCodeFlag)!='i') continue;
    if (*((char *)ReadBuff+il+9*UniCodeFlag)!='o') continue;
    if (*((char *)ReadBuff+il+10*UniCodeFlag)!='n') continue;
    // Found it! Save it!
    il=il+14*UniCodeFlag-2;
    i=0;
    while (*((char *)ReadBuff+il)!='\0')
          {
          FoundFV[i]=*((char *)ReadBuff+il);
          il+=UniCodeFlag;
          i+=1;
          }
    FoundFV[i]='\0';
    break;
    }
free(ReadBuff);
if (FoundFV[0]=='\0')
   {
   strcpy(RetMsg,"%4%,%FileVersion not found%");
   goto DoReturn;
   }
strcpy(RetMsg,"%0%,%");
strcat(RetMsg,FoundFV);
strcat(RetMsg,"%");
goto DoReturn;


/////////////////////////////////////////////////////////////////
DoReturn:
logit("GetFileVer returning");
close(FileHan);
strcpy(RetStr->strptr,RetMsg);
RetStr->strlength=(ULONG)strlen(RetMsg);
return 0l;
}
0
 
LVL 86

Expert Comment

by:jkr
ID: 6968990
0
 
LVL 22

Expert Comment

by:cookre
ID: 6969437
Bingo.

(Now if only I could find the 'delete my previous post' button...)
0
Salesforce Made Easy to Use

On-screen guidance at the moment of need enables you & your employees to focus on the core, you can now boost your adoption rates swiftly and simply with one easy tool.

 
LVL 7

Author Comment

by:peterchen092700
ID: 6969565
almost good jkr ;)
do you know of any samples that show how to walk the VERSIONINFO resource? Updating the FileVersion DWORD's should be no problem - but the strings....
0
 
LVL 7

Author Comment

by:peterchen092700
ID: 6969579
cookre: Don't worry ;) Your code in "9x, too" - however, I need to update the "FileVersion" string too - and this one might get longer :--(
0
 
LVL 86

Accepted Solution

by:
jkr earned 50 total points
ID: 6969590
Hmm, it should be similar to the sample:

result = UpdateResource(hUpdateRes,       // update resource handle
     RT_VERSION,                   // change version resource
     "VERSIONINFO",                  // resource name
     MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),  // neutral language
     lpResLock,                   // ptr to resource info
     SizeofResource(hExe, hRes)); // size of resource info.
0
 
LVL 7

Author Comment

by:peterchen092700
ID: 7026630
thanks & sorry for the late come-back
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article surveys and compares options for encoding and decoding base64 data.  It includes source code in C++ as well as examples of how to use standard Windows API functions for these tasks. We'll look at the algorithms — how encoding and decodi…
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question