Click here to Skip to main content
15,860,972 members
Articles / Desktop Programming / MFC

Target Eye Revealed: Part 1 - Target Eye's Unique AutoUpdate Mechanism

Rate me:
Please Sign up or sign in to vote.
4.99/5 (58 votes)
12 Jun 2014CPOL9 min read 125.3K   1.6K   102   42
How Target Eye's Auto updating mechanism allows a silent update of an application from identifying newer versions, downloading them and running them instead of the old one
This article focuses on only one aspect of Target Eye, which is the Auto Update mechanism. This mechanism is used for silently updating the Target Eye Secret Agent whenever there is a newer version available on the server.

Introduction

Auto Update mechanism doesn't have to be based on the actual version number (kept in the Version String), but can also base on the Last Modified Date Stamp of the newer version compared to the old one. Target Eye Monitoring System, developed from 2000 until 2010, had such mechanism. The next article in this series is about Target Eye's screen capturing and the third one is about the Shopping List mechanism. The fourth article is about Keyboard Capturing. The fifth article is about the Cover Story mechanism. The sixth article is about hiding files the Target Eye way.

Background

Target Eye Monitoring System, which I have developed 12 years ago, was one of the first surveillance and monitoring tools for capturing activity of remote computers. The following description is taken from the original Business Plan of this venture:

Image 1

Target Eye Monitoring System

Target Eye is a start-up company whose mission is to develop integrated software solutions for real-time monitoring of remote PCs, which are based on the company’s patent pending technologies (60/204,084 and 60/203,832). Our major product, Target Eye Monitoring System, is a software product that can continuously track, record, playback, analyze and report any activity performed on one or multiple remote PCs, in a way which is undetectable by their users. The software relies on a stream of rapidly captured, compressed full-screen images and continuous keystroke capturing to provide a comprehensive and accurate account of user activities, including local activities which do not generate any network traffic. In this way, the software can track and record activities, which are undetectable by systems relying on network traffic analysis. A smart agent module running on the monitored PCs uses a rule base to send alerts to the monitoring location(s) or perform pre-defined local operations. Monitoring can be performed from multiple locations. Major markets are law-enforcement.

Target Eye Monitoring System was developed with an auto update mechanism. This mechanism allows smooth and silent (un-attendant) execution of the new version instead of the current one.

Image 2

An historical image: The first version of Target Eye (April 2000)

Image 3

A more recent version (Target Eye 2007)

Target Eye's Building Blocks

There are several terms and building blocks that sums up to the Target Eye Monitoring System:

  • Target Eye Secret Agent - the covert part of the product that runs on the monitored computer
  • Target Eye Operator - the authority that operates the Secret Agent (for example: a Law Enforcement agency).
  • A Mission - a request to perform an action. There are many possible actions (for example, capturing the screen, as described in another article of mine or searching and finding files, as described in this article).
  • Target Eye Compiler - The tool that is used by the Target Eye Operator to customize a Secret Agent for performing specific tasks.

About this Article

This article focuses on only one aspect of this product, which is the Auto Update mechanism. This mechanism is used for silently updating the Target Eye Secret Agent whenever there is a newer version available on the server.

Creating and Marking Incremental Versions

In order to be able to determine a newer version over the current one, there must be a mechanism to mark the various versions, to increment the version number, and to examine the version of a given executable.

The most common way of doing so is using the "Version String" resource, and to use a prebuild automated tool to promote this string each time the application is built.

I used another method which is based on the list modification date of the executable file. This method has its pros and cons, but can be useful for most cases, since it will allow your end users to get any version of your application that was built after the one that is currently installed.

Before I explain, it is important to mention two global variables which are used to build at start:

C++
strRegularLocation   

The location and full path of the application when it runs normally (i.e., c:\program files\your app name\your app.exe),

and…

C++
strTemporaryLocation 

Another full path to be used for the temporary version downloaded when there is an update.

The reason for doing so is because since the application downloads its new version, the new version can't be downloaded to its current location, and can't replace itself because while a file is used (or an application is running), the file is locked and can't be moved, deleted or renamed.

C++
char strRegularLocation[256];
char strTemporaryLocation[256];

Filling strRegularLocation and strTemporaryLocation with real values.

strRegularLocation is taken simply from __argv[0], provided that we are sure that we aren't running already from the temporary location. We ensure that by using a parameter named "INSTALL" which will be explained later.

strTemporaryLocation is built using a common folder and a temporary name combined. We use GetSpecialFolder() to find the path name of this folder in any computer running the application.

Getting the Date Stamp of Current Version

To do so, TEGetVersion(), the first building block, is used and returns a CString containing the last modification date of a given file.

C++
//
TEGetVersion returns the last modification date / time of a given file
CString
TEGetVersion (CString FileName) 
{  
         CFileStatus status1;
         CTime Time1;
         if( CFile::GetStatus( FileName, status1) )
         {        
                 Time1 = status1.m_mtime; 
                 return (Time1.Format("%d%m%M%S"));
         } 
         // Failed 
         return ((CString)"");
}
//

When my application starts, I store the date / time stamp of it somewhere.

C++
TE_Options.Version=TEGetVersion((CString)__argv[0]);
// here we keep the date/time stamp of the current version

Now we need to get the date / time stamp of the file online, preferably, without having to download it first, so we only download when we need to update to a newer version.

C++
HINTERNET FileHandle=NULL; 
       
WIN32_FIND_DATA ftpFileData; 
//find the file on the ftp server 
       
FileHandle= FtpFindFirstFile( m_ftpHandle, FTP_NEWVERSION, &ftpFileData,
INTERNET_FLAG_RELOAD, 0 );
if( NULL != FileHandle )
{
       
    // get the write time of the ftp file
       
    SYSTEMTIME ftpFileWriteTime, stUTC1;
       
    FILETIME ftp;
       
    FileTimeToSystemTime( &ftpFileData.ftLastWriteTime, &stUTC1 );
       
    SystemTimeToTzSpecificLocalTime( NULL, &stUTC1, &ftpFileWriteTime );
}

We need to define how old the current versionshould be in order to update it. Again, this approach can be very useful in some cases and less useful in other cases. For example, if your application involves a database, you might be interested to ensure that the database is always most recent and never older than 3 days.

C++
#define UPDATEEVERY  60*24*7 // 7 days
#define APP_EXE_NAME "TargetEyeTest.exe"
#define FTP_NEWVERSION "NewVersion.exe"
#define APP_REGULAR_FOLDER "\\TargetEye\\"

The next step is to compare the date / time stamp of each file.

C++
CFileStatus
statusOld;
CTime TimeOld;
if( CFile::GetStatus( FileHandle, statusOld ) )
{
	CTime ct,OldTime;
    	OldTime=statusOld.m_mtime;
	hFindFile.GetLastWriteTime(ct);
	LONG Diff;
	ver=ct.FormatGmt("%d %m %Y %H:%M %Z");
	oldver=OldTime.FormatGmt("%d %m %Y %H:%M %Z");
 	Diff = ((CTimeSpan)(ct-OldTime)).GetTotalMinutes();
 	hFindFile.Close();
 	if (Diff>UPDATEEVERY || resultSpecific)
 	{
        // download the newer version
 	}
} 

Downloading the New Version

Downloading the newer version is performed using TE_DownladLoad() which is listed here. We make several attempts in case there is a temporary block or communication problem.

C++
#define FTPRETRIES 5 // number of retries
BOOL TE_DownloadLoad(char *FtpFileName,char *LocalFileName)
{
     int DoTry=FTPRETRIES; 
     int result; 
     TryAgain:; 
     try 
     {
         result = MyConnection.m_FtpConn->GetFile(FtpFileName, LocalFileName, FALSE);
     }
     catch (CInternetException* pEx)
     {
        TCHAR sz[1024]; 
        pEx->GetErrorMessage(sz,1024);
        WriteToLog("Error %s\n", sz);
        if(TE_DEBUG) MessageBox(NULL,sz,"Error 6 - TE_Load",MB_OK);
        pEx->Delete(); 
     }
     if (!result)
     {
         if(DoTry-- >0) goto TryAgain;
         return(FALSE);
     }
     else     
     {
           return (TRUE);
     }
}

Now we are ready to switch between the currently running version (the old one) with the newer one.

Executing the Newer Version

C++
BOOL ExecuteNewVersion(char *ExeName,char *Param)
{
     STARTUPINFO sinfo;
     PROCESS_INFORMATION  pinfo;
     ZeroMemory(&sinfo, sizeof(sinfo));
     sinfo.cb = sizeof(sinfo); 
     sinfo.lpDesktop= "WinSta0\\Default";
     sinfo.dwFlags=STARTF_USESHOWWINDOW ;
     sinfo.wShowWindow=SW_SHOW;
     if(!CreateProcess(NULL,(char*)(LPCTSTR)((CString)(ExeName)+(CString)"
         "+(CString)(Param)), NULL, NULL,FALSE,NORMAL_PRIORITY_CLASS |
         CREATE_NEW_CONSOLE, NULL, NULL, &sinfo, &pinfo))
     {
           char s[256];
           sprintf(s,"Can't execute program: %s params %s",ExeName,Param);
           // ERROR LOG
           TELog.LogError("Execute New Version",s,0);
           return FALSE;
     }
     else
     {                                  
           return TRUE;
     }
} 

So if we put all the code together, we get:

C++
CFileStatus statusOld;
CTime TimeOld;
if(CFile::GetStatus( FileHandle, statusOld ) )
{
     CTime ct,OldTime;
     OldTime=statusOld.m_mtime;
     hFindFile.GetLastWriteTime(ct);
     LONG Diff;
     ver=ct.FormatGmt("%d %m %Y %H:%M %Z");
     oldver=OldTime.FormatGmt("%d %m %Y %H:%M %Z");
     Diff = ((CTimeSpan)(ct-OldTime)).GetTotalMinutes();
     hFindFile.Close();        
     if (Diff>UPDATEEVERY || resultSpecific)
     { 
         // downloading the newer version
         if(TE_DownLoad((resultGeneric)?NEWEXESTR:NEWEXE,TEMPPLACE))
         {
              // We have successfully downloaded the newer version
              if(ExecuteNewVersion(TEMPPLACE,"INSTALL"))
              {
                  // We have successfully executed the
                  // newer version. Current version can now quit
              }
              else
              // Failed to execute new version
          }
         else
         {
            TELog.LogError("New Ftp version found","Can't download",0);
         }
     }
}

The TE_Init() Function

TE_Init() is used to determine the parameters used when application was executed (unlike the full version of Target Eye Monitoring System, which is much more complex, in our example, there is one optional parameter – "INSTALL").

C++
if(__argc>1) 
{
     if(strcmp(__argv[1],"INSTALL")==0)
     {
        // TE_FirstTime(); -> here you can place code you wish to
        //be executed only during the first run 
     }
}
else
// No parameters
{
     // Delete a temporary version if exists at the temporary location
}

Replacing Old With New

In order to quit in a normal fashion, without missing anything we wish to do before quitting, the main even loop contains a check for the value of NeedToQuit, which would normally be FALSE.

C++
BOOL NeedToQuit=FALSE; 

When NeedToQuit becomes TRUE, the application will perform any routine required before quitting (for example, saving unsaved work). For example:

C++
if(NeedToQuit)
{
     if(TE_DEBUG)
         MessageBox(NULL,"Terminating Targe Eye",
           "Target Eye Monitoring System",NULL);
        return FALSE;
} 

Further, the application expects to be executed either with the "INSTALL" parameter as part of the command line, or without it. The following scheme illustrates the flow of an installation of a newer version to a temporary location (the Desktop folder, in our example), up to the moment the temporary file used for it is deleted. This requires several stages:

The Target Eye Cycle

Stage Ran with Parameter Ran from location Description
1 None Regular The current (old) version is running before the newer version is available
2     The newer version checks if there is a temporary copy of itself at the temporary location, but there isn't any
3     A newer version is found
4     Newer version is downloaded to a temporary location
5     Newer version runs from the temporary location with the "INSTALL" parameter.
6     Current version quits
7 INSTALL Temporary The newer application ran from the temporary location copies itself to the regular location, replacing the old version which quitted (5)
8     The newer version runs the copy located in the regular location and quits.
9 None Regular The newer version checks if there is a temporary copy of itself at the temporary location, and deletes it.

Image 4

Choosing an FTP Server for this Demo

In order to use the source code that is attached to this article, there are predefined settings of a public Secured FTP server available to the public by Chilkat Software, Inc.

The details of this server are:

Secure FTP Server Details

Type FileZilla
Address ftp.secureftp-test.com
Login Test
Password Test

There is a file there named hamlet.xml which can be used for testing a remote file date stamp.

Internationalization

To comply with scenarios in which there are users worldwide, and yet we wish to release a version to be available at the same moment to all of them regardless of their local time, we use:

FormatGmt 

GMT is an absolute time reference and doesn't change regardless of the season or the location. FormatGmt is used like that:

C++
CTime t( 1999, 3, 19, 22, 15, 0 );
// 10:15 PM March 19, 1999
CString s = t.Format( "%A, %B %d, %Y" );
ATLASSERT( s == "Friday, March 19, 1999" );

Limiting to a Single Instance

The mechanism described in this article can only work if we limit our application to run only once at any given moment. To do so, several methods can be used, such as CreateMutex().

See http://support.microsoft.com/kb/243953

Target Eye Monitoring System uses a different and a bit "brutal" approach, which will be explained in detail over another article. Basically, Target Eye Monitoring System searches for other instances currently running in memory, and when found, does one of the two following options:

  1. If the instance found is newer, the current running instance quits.
  2. If the instance found is older, the current running instance kills it.

To explain, let's consider the following scenario. An end user had his current copy of software updated to a newer one. A day after, this end user runs the original CD of the software. The version that resides on the original CD, will search for new updates at the FTP server, which is unnecessary. Further, if the application runs constantly (like a monitoring application should), then probably when the CD version is run, there is also another newer version already running. To address such scenario and other scenarios, we should take the necessary measures to ensure that an application will always be up to date.

Further Reading

History

  • 4th January, 2012: Initial version

©2000-2010 Target Eye LTD (UK)

All materials contained on this article are protected by International copyright law and may not be used, reproduced, distributed, transmitted, displayed, published or broadcast without the prior written permission given by Target Eye LTD (UK). You may not alter or remove any trademark, copyright or other notice from copies of the content.

Michael Haephrati , CodeProject MVP 2013

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO Secured Globe, Inc.
United States United States
Michael Haephrati is a music composer, an inventor and an expert specializes in software development and information security, who has built a unique perspective which combines technology and the end user experience. He is the author of a the book Learning C++ , which teaches C++ 20, and was published in August 2022.

He is the CEO of Secured Globe, Inc., and also active at Stack Overflow.

Read our Corporate blog or read my Personal blog.





Comments and Discussions

 
GeneralMy vote of 5 Pin
PVX0079-Sep-15 7:34
PVX0079-Sep-15 7:34 
QuestionGreat article Pin
Weissman Shimon23-Jun-14 9:50
Weissman Shimon23-Jun-14 9:50 
AnswerRe: Great article Pin
Michael Haephrati23-Jun-14 10:38
professionalMichael Haephrati23-Jun-14 10:38 
GeneralMy vote of 5 Pin
Jim Forst6-Oct-13 5:50
Jim Forst6-Oct-13 5:50 
Questionfatal error LNK1123: failure during conversion to COFF: file invalid or corrupt Pin
Member 103184646-Oct-13 3:20
Member 103184646-Oct-13 3:20 
AnswerRe: fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt Pin
Michael Haephrati6-Oct-13 3:30
professionalMichael Haephrati6-Oct-13 3:30 
AnswerRe: fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt Pin
Michael Haephrati6-Oct-13 3:39
professionalMichael Haephrati6-Oct-13 3:39 
GeneralRe: fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt Pin
Member 102681836-Oct-13 4:06
Member 102681836-Oct-13 4:06 
GeneralRe: fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt Pin
Michael Haephrati6-Oct-13 4:17
professionalMichael Haephrati6-Oct-13 4:17 
AnswerRe: fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt Pin
Jim Forst6-Oct-13 5:47
Jim Forst6-Oct-13 5:47 
AnswerRe: fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt Pin
వేంకటనారాయణ(venkatmakam)13-Jun-14 3:33
వేంకటనారాయణ(venkatmakam)13-Jun-14 3:33 
AnswerRe: fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt Pin
Weissman Shimon23-Jun-14 9:53
Weissman Shimon23-Jun-14 9:53 
GeneralMy vote of 5 Pin
alonbarak14-Jun-13 11:01
alonbarak14-Jun-13 11:01 
GeneralMy vote of 5 Pin
panshoup13-Mar-13 3:09
panshoup13-Mar-13 3:09 
GeneralRe: My vote of 5 Pin
Michael Haephrati13-Mar-13 3:11
professionalMichael Haephrati13-Mar-13 3:11 
GeneralRe: My vote of 5 Pin
panshoup13-Mar-13 3:20
panshoup13-Mar-13 3:20 
GeneralRe: My vote of 5 Pin
Michael Haephrati13-Mar-13 3:22
professionalMichael Haephrati13-Mar-13 3:22 
GeneralRe: My vote of 5 Pin
panshoup13-Mar-13 3:29
panshoup13-Mar-13 3:29 
GeneralRe: My vote of 5 Pin
Michael Haephrati13-Mar-13 3:27
professionalMichael Haephrati13-Mar-13 3:27 
祝你好运,你的英语
GeneralMy vote of 5 Pin
Member 416352421-Feb-13 5:29
Member 416352421-Feb-13 5:29 
GeneralMy vote of 5 Pin
liliflower35525-Jan-13 1:08
liliflower35525-Jan-13 1:08 
GeneralMy vote of 5 Pin
resi243125-Jan-13 0:07
resi243125-Jan-13 0:07 
GeneralMy vote of 5 Pin
midulm24-Jan-13 23:04
midulm24-Jan-13 23:04 
GeneralMy vote of 5 Pin
balam198824-Jan-13 22:18
balam198824-Jan-13 22:18 
GeneralMy vote of 5 Pin
evan89724-Jan-13 21:39
evan89724-Jan-13 21:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.