Solved

Modify resource of binary

Posted on 2002-04-25
7
306 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
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
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

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

This article shows how to make a Windows 7 gadget that extends its U/I with a flyout panel -- a window that pops out next to the gadget.  The example gadget shows several additional techniques:  How to automatically resize a gadget or flyout panel t…
If you have ever found yourself doing a repetitive action with the mouse and keyboard, and if you have even a little programming experience, there is a good chance that you can use a text editor to whip together a sort of macro to automate the proce…
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…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

708 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

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now