Solved

Modify resource of binary

Posted on 2002-04-25
7
325 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

 
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

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

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

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…
With most software applications trying to cater to multiple user needs nowadays, the focus is to make them as configurable as possible. For e.g., when creating Silverlight applications which will connect to WCF services, the service end point usuall…
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…
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…

632 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