• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 345
  • Last Modified:

Modify resource of binary

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
peterchen092700
Asked:
peterchen092700
  • 3
  • 2
  • 2
1 Solution
 
cookreCommented:
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
 
jkrCommented:
0
 
cookreCommented:
Bingo.

(Now if only I could find the 'delete my previous post' button...)
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
peterchen092700Author Commented:
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
 
peterchen092700Author Commented:
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
 
jkrCommented:
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
 
peterchen092700Author Commented:
thanks & sorry for the late come-back
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

  • 3
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now