?
Solved

Error C2197: 'FARPROC', I need a soliution

Posted on 2008-01-28
17
Medium Priority
?
1,131 Views
Last Modified: 2013-11-20
Hello.
I can't get this c code work in visual cpp compiler.

I found this information:
http://support.microsoft.com/kb/117428

Could anyone tell me what I need to edit here?

Thanks in advance.
//
//	selfdel.c
//
//	Self deleting executable for Win9x/WinNT (all versions)
//
//	J Brown 1/10/2003
//
//	This source file must be compiled with /GZ turned OFF
//  (basically, disable run-time stack checks)
//
//	Under debug build this is always on (MSVC6)
//
//
#include <windows.h>
#include <tchar.h>
 
#pragma pack(push, 1)
 
#define CODESIZE 0x200
 
//
//	Structure to inject into remote process. Contains 
//  function pointers and code to execute.
//
typedef struct _SELFDEL
{
	struct _SELFDEL *Arg0;			// pointer to self
 
	BYTE	opCodes[CODESIZE];		// code 
 
	HANDLE	hParent;				// parent process handle
 
	FARPROC	fnWaitForSingleObject;
	FARPROC	fnCloseHandle;
	FARPROC	fnDeleteFile;
	FARPROC	fnSleep;
	FARPROC	fnExitProcess;
	FARPROC fnRemoveDirectory;
	FARPROC fnGetLastError;
 
	BOOL	fRemDir;
 
	TCHAR	szFileName[MAX_PATH];	// file to delete
 
} SELFDEL;
 
#pragma pack(pop)
 
#ifdef _DEBUG
#define FUNC_ADDR(func) (PVOID)(*(DWORD *)((BYTE *)func + 1) + (DWORD)((BYTE *)func + 5))
#else
#define FUNC_ADDR(func) func
#endif
 
//
//	Routine to execute in remote process. 
//
static void remote_thread(SELFDEL *remote)
{
	// wait for parent process to terminate
	remote->fnWaitForSingleObject(remote->hParent, INFINITE);
	remote->fnCloseHandle(remote->hParent);
 
	// try to delete the executable file 
	while(!remote->fnDeleteFile(remote->szFileName))
	{
		// failed - try again in one second's time
		remote->fnSleep(1000);
	}
 
	// finished! exit so that we don't execute garbage code
	remote->fnExitProcess(0);
}
 
//
//	Delete currently running executable and exit
//	
BOOL SelfDelete(BOOL fRemoveDirectory)
{
	STARTUPINFO			si = { sizeof(si) };
	PROCESS_INFORMATION pi;
 
	CONTEXT				context;
	DWORD				oldProt;
	SELFDEL				local;
	DWORD				entrypoint;
 
	TCHAR				szExe[MAX_PATH] = _T("explorer.exe");
 
	//
	//	Create executable suspended
	//
	if(CreateProcess(0, szExe, 0, 0, 0, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, 0, 0, &si, &pi))
	{
		local.fnWaitForSingleObject		= (FARPROC)WaitForSingleObject;
		local.fnCloseHandle				= (FARPROC)CloseHandle;
		local.fnDeleteFile				= (FARPROC)DeleteFile;
		local.fnSleep					= (FARPROC)Sleep;
		local.fnExitProcess				= (FARPROC)ExitProcess;
		local.fnRemoveDirectory			= (FARPROC)RemoveDirectory;
		local.fnGetLastError			= (FARPROC)GetLastError;
 
		local.fRemDir					= fRemoveDirectory;
 
		// Give remote process a copy of our own process handle
		DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), 
			pi.hProcess, &local.hParent, 0, FALSE, 0);
 
		GetModuleFileName(0, local.szFileName, MAX_PATH);
 
		// copy in binary code
		memcpy(local.opCodes, FUNC_ADDR(remote_thread), CODESIZE);
 
		//
		// Allocate some space on process's stack and place
		// our SELFDEL structure there. Then set the instruction pointer 
		// to this location and let the process resume
		//
		context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
		GetThreadContext(pi.hThread, &context);
 
		// Allocate space on stack (aligned to cache-line boundary)
		entrypoint = (context.Esp - sizeof(SELFDEL)) & ~0x1F;
		
		//
		// Place a pointer to the structure at the bottom-of-stack 
		// this pointer is located in such a way that it becomes 
		// the remote_thread's first argument!!
		//
		local.Arg0 = (SELFDEL *)entrypoint;
 
		context.Esp = entrypoint - 4;	// create dummy return address
		context.Eip = entrypoint + 4;	// offset of opCodes within structure
 
		// copy in our code+data at the exe's entry-point
		VirtualProtectEx(pi.hProcess,   (PVOID)entrypoint, sizeof(local), PAGE_EXECUTE_READWRITE, &oldProt);
		WriteProcessMemory(pi.hProcess, (PVOID)entrypoint, &local, sizeof(local), 0);
 
		FlushInstructionCache(pi.hProcess, (PVOID)entrypoint, sizeof(local));
 
		SetThreadContext(pi.hThread, &context);
 
		// Let the process continue
		ResumeThread(pi.hThread);
		CloseHandle(pi.hThread);
		CloseHandle(pi.hProcess);
 
		return TRUE;
	}
 
	return FALSE;
}
 
 
int main(void)
{
	SelfDelete(TRUE);
	return 0;
}

Open in new window

0
Comment
Question by:makasbrg
  • 10
  • 5
  • 2
17 Comments
 
LVL 53

Expert Comment

by:Infinity08
ID: 20766274
What line does the error point to ?
0
 

Author Comment

by:makasbrg
ID: 20766284
error C2197: 'FARPROC' : too many arguments for call through pointer-to-function
Lines: 61, 62, 65

fatal error C1903: unable to recover from previous error(s); stopping compilation

0
 
LVL 53

Accepted Solution

by:
Infinity08 earned 1000 total points
ID: 20766294
Probably these :

                local.fnWaitForSingleObject             = (FARPROC)WaitForSingleObject;
                local.fnCloseHandle                             = (FARPROC)CloseHandle;
                local.fnDeleteFile                              = (FARPROC)DeleteFile;
                local.fnSleep                                   = (FARPROC)Sleep;
                local.fnExitProcess                             = (FARPROC)ExitProcess;
                local.fnRemoveDirectory                 = (FARPROC)RemoveDirectory;
                local.fnGetLastError                    = (FARPROC)GetLastError;

FARPROC is a pointer to a function that takes no arguments and returns an int.

You're trying to assign different types of functions to it ... You need to use the proper function pointer typedefs. For example, for WaitForSingleObject, that would be :

        typedef DWORD (*FunPtrToWFSO)(HANDLE, DWORD);

ie. a pointer to a function taking a HANDLE and a DWORD as arguments and returning a DWORD. Then :

        FunPtrToWFSO fnWaitForSingleObject;

and you can assign the function pointer :

        local.fnWaitForSingleObject = (FunPtrToWFSO) WaitForSingleObject;

Similarly for the others.
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
LVL 53

Expert Comment

by:Infinity08
ID: 20766298
>> Lines: 61, 62, 65

Yes, that would be the result of using the wrong function pointer typedef ;)
0
 

Author Comment

by:makasbrg
ID: 20766427
I am only begginer so I guess I will need some more help :\

I modified code like shown, code compiles, but program crashes on execution and doesn't delete itself.


I also get these warnings:
12.cpp(123) : warning C4311: 'type cast' : pointer truncation from 'BYTE *' to 'DWORD'
12.cpp(123) : warning C4312: 'type cast' : conversion from 'unsigned long' to 'PVOID' of greater size
12.cpp(141) : warning C4312: 'type cast' : conversion from 'DWORD' to 'SELFDEL *' of greater size
12.cpp(147) : warning C4312: 'type cast' : conversion from 'DWORD' to 'PVOID' of greater size
12.cpp(148) : warning C4312: 'type cast' : conversion from 'DWORD' to 'PVOID' of greater size
12.cpp(150) : warning C4312: 'type cast' : conversion from 'DWORD' to 'PVOID' of greater size
#include "stdafx.h"
//	Self deleting executable for Win9x/WinNT (all versions)
//
//	J Brown 1/10/2003
//
//	This source file must be compiled with /GZ turned OFF
//  (basically, disable run-time stack checks)
//
//	Under debug build this is always on (MSVC6)
//
//
#include <windows.h>
#include <tchar.h>
 
#pragma pack(push, 1)
 
#define CODESIZE 0x200
 
//
//	Structure to inject into remote process. Contains 
//  function pointers and code to execute.
//
typedef DWORD (*PWaitForSingleObject)(HANDLE, DWORD);
PWaitForSingleObject fnWaitForSingleObject;
typedef DWORD (*PCloseHandle)(HANDLE);
PCloseHandle fnCloseHandle;
typedef DWORD (*PSleep)(int);
PSleep fnSleep;
typedef DWORD (*PDeleteFile)(TCHAR[260]);
PDeleteFile fnDeleteFile;
typedef DWORD (*PExitProcess)(int);
PExitProcess fnExitProcess;
 
 
typedef struct _SELFDEL
{
	struct _SELFDEL *Arg0;			// pointer to self
 
	BYTE	opCodes[CODESIZE];		// code 
 
	HANDLE	hParent;				// parent process handle
 
	(PWaitForSingleObject) fnWaitForSingleObject;
	(PCloseHandle) fnCloseHandle;
	(PDeleteFile) fnDeleteFile;
	(PSleep) fnSleep;
	(PExitProcess) fnExitProcess;
	(PCloseHandle) fnRemoveDirectory;
	(PCloseHandle) fnGetLastError;
 
	BOOL	fRemDir;
 
	TCHAR	szFileName[MAX_PATH];	// file to delete
 
} SELFDEL;
 
#pragma pack(pop)
 
#ifdef _DEBUG
#define FUNC_ADDR(func) (PVOID)(*(DWORD *)((BYTE *)func + 1) + (DWORD)((BYTE *)func + 5))
#else
#define FUNC_ADDR(func) func
#endif
 
 
//
//	Routine to execute in remote process. 
//
static void remote_thread(SELFDEL *remote)
{
	// wait for parent process to terminate
	remote->fnWaitForSingleObject(remote->hParent, INFINITE);
	remote->fnCloseHandle(remote->hParent);
 
	// try to delete the executable file 
	while(!remote->fnDeleteFile(remote->szFileName))
	{
		// failed - try again in one second's time
		remote->fnSleep(1000);
	}
 
	// finished! exit so that we don't execute garbage code
	remote->fnExitProcess(0);
}
 
//
//	Delete currently running executable and exit
//	
BOOL SelfDelete(BOOL fRemoveDirectory)
{
	STARTUPINFO			si = { sizeof(si) };
	PROCESS_INFORMATION pi;
 
	CONTEXT				context;
	DWORD				oldProt;
	SELFDEL				local;
	DWORD				entrypoint;
 
	TCHAR				szExe[MAX_PATH] = _T("explorer.exe");
 
	//
	//	Create executable suspended
	//
	if(CreateProcess(0, szExe, 0, 0, 0, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, 0, 0, &si, &pi))
	{
		local.fnWaitForSingleObject		= (PWaitForSingleObject)WaitForSingleObject;
		local.fnCloseHandle				= (PCloseHandle)CloseHandle;
		local.fnDeleteFile				= (PDeleteFile)DeleteFile;
		local.fnSleep					= (PSleep)Sleep;
		local.fnExitProcess				= (PExitProcess)ExitProcess;
		local.fnRemoveDirectory			= (PCloseHandle)RemoveDirectory;
		local.fnGetLastError			= (PCloseHandle)GetLastError;
 
		local.fRemDir					= fRemoveDirectory;
 
		// Give remote process a copy of our own process handle
		DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), 
			pi.hProcess, &local.hParent, 0, FALSE, 0);
 
		GetModuleFileName(0, local.szFileName, MAX_PATH);
 
		// copy in binary code
		memcpy(local.opCodes, FUNC_ADDR(remote_thread), CODESIZE);
 
		//
		// Allocate some space on process's stack and place
		// our SELFDEL structure there. Then set the instruction pointer 
		// to this location and let the process resume
		//
		context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
		GetThreadContext(pi.hThread, &context);
 
		// Allocate space on stack (aligned to cache-line boundary)
		entrypoint = (context.Esp - sizeof(SELFDEL)) & ~0x1F;
		
		//
		// Place a pointer to the structure at the bottom-of-stack 
		// this pointer is located in such a way that it becomes 
		// the remote_thread's first argument!!
		//
		local.Arg0 = (SELFDEL *)entrypoint;
 
		context.Esp = entrypoint - 4;	// create dummy return address
		context.Eip = entrypoint + 4;	// offset of opCodes within structure
 
		// copy in our code+data at the exe's entry-point
		VirtualProtectEx(pi.hProcess,   (PVOID)entrypoint, sizeof(local), PAGE_EXECUTE_READWRITE, &oldProt);
		WriteProcessMemory(pi.hProcess, (PVOID)entrypoint, &local, sizeof(local), 0);
 
		FlushInstructionCache(pi.hProcess, (PVOID)entrypoint, sizeof(local));
 
		SetThreadContext(pi.hThread, &context);
 
		// Let the process continue
		ResumeThread(pi.hThread);
		CloseHandle(pi.hThread);
		CloseHandle(pi.hProcess);
 
		return TRUE;
	}
 
	return FALSE;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
	SelfDelete(TRUE);
	return 0;
}

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20766494
>> I also get these warnings:

The first two are because of your FUNC_ADDR macro :

        #define FUNC_ADDR(func) (PVOID)(*(DWORD *)((BYTE *)func + 1) + (DWORD)((BYTE *)func + 5))

func is a function address - you can't just cast it to BYTE*. You also can't just cast a BYTE* to a DWORD. What is this macro supposed to do ?


>> 12.cpp(141) : warning C4312: 'type cast' : conversion from 'DWORD' to 'SELFDEL *' of greater size

points to this line :

            local.Arg0 = (SELFDEL *)entrypoint;

entrypoint is defined as a DWORD ... You can't just cast it to a pointer. You really have to use the proper types everywhere. You probably don't want entrypoint to be a DWORD, but rather a SELFDEL* (or at least a compatible pointer type).


>> 12.cpp(147) : warning C4312: 'type cast' : conversion from 'DWORD' to 'PVOID' of greater size
>> 12.cpp(148) : warning C4312: 'type cast' : conversion from 'DWORD' to 'PVOID' of greater size
>> 12.cpp(150) : warning C4312: 'type cast' : conversion from 'DWORD' to 'PVOID' of greater size

Similarly, you try to cast a DWORD (entrypoint) to a pointer type (PVOID) ...
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20766500
>> but program crashes on execution and doesn't delete itself.

What's the exact crash message ? If you run it in a debugger, what line does it crash on ?
0
 

Author Comment

by:makasbrg
ID: 20766520
>      12.exe!memcpy(unsigned char * dst=0x0012f794, unsigned char * src=0xecc30b50, unsigned long count=512)  Line 171      Asm
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20766556
>> >      12.exe!memcpy(unsigned char * dst=0x0012f794, unsigned char * src=0xecc30b50, unsigned long count=512)  Line 171      Asm

Yes, that's most likely related to your FUNC_ADDR macro - see my previous post.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20766562
Notice that 0xecc30b50 is probably not a valid address ...
0
 

Author Comment

by:makasbrg
ID: 20766577
I left only
#define FUNC_ADDR(func) func
and it doesn't crash.

But, unfortunately, program doesn't work as it should (doesn't delete itself).

There are these warnings:
12.cpp(138) : warning C4312: 'type cast' : conversion from 'DWORD' to 'SELFDEL *' of greater size
12.cpp(144) : warning C4312: 'type cast' : conversion from 'DWORD' to 'PVOID' of greater size
12.cpp(145) : warning C4312: 'type cast' : conversion from 'DWORD' to 'PVOID' of greater size
12.cpp(147) : warning C4312: 'type cast' : conversion from 'DWORD' to 'PVOID' of greater size
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20766588
>> and it doesn't crash.

And does the FUNC_ADDR macro still do what you want it to do ? What was that btw ?


>> But, unfortunately, program doesn't work as it should (doesn't delete itself).

What do you mean by "delete itself" ?


>> There are these warnings:

See my earlier post ... I already addresses these ;)
0
 

Author Comment

by:makasbrg
ID: 20766600
>> And does the FUNC_ADDR macro still do what you want it to do ? What was that btw ?
Well, this isn't my code, I don't know what it should do :x
I'm just trying to get it work in vc++

>>What do you mean by "delete itself" ?
Program should delete itself when executed ("Self deleting executable").

>>>> There are these warnings:
>>See my earlier post ... I already addresses these ;)
I don't know how to fix them :x Is it possible that because of these program doesn't work?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20766676
>> Program should delete itself when executed ("Self deleting executable").

I assume this is where you got the code from :

        http://www.catch22.net/tuts/selfdel.asp

Did you compile it as C or as C++ ? It should be compiled with a C compiler ...

In any case, the technique used seems pretty dodgy to me, and I wouldn't recommend using it ...
Take a look at the other techniques presented on the same page - they might be more interesting ...


>> Is it possible that because of these program doesn't work?

Well, if you're not sure what the code does, then it's entirely possible that some of the code is not doing what it's supposed to do ;)

Using proper types all the time will solve a lot of problems. Changing entrypoint to a SELFDEL* for example will get rid of those warnings.
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 1000 total points
ID: 20769187
Help, that code is overkill... Jeffrey Richter introduced the following for the same purpose:
#include <Windows.h>
#include <stdlib.h>
#include <tchar.h>
 
/////////////////////////////////////////////////////////////////////
 
int WINAPI WinMain(HINSTANCE h, HINSTANCE h2, LPSTR psz, int n) {
 
   // Is this the original EXE ther Clone?
   // The original EXE receives one argument,
   // the clone more.
   if (__argc == 1) {
 
      // Original EXE: Start the Clone.
 
      // Copy EXE to the temporary directory
      TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH];
      GetModuleFileName(NULL, szPathOrig, _MAX_PATH);
      GetTempPath(_MAX_PATH, szPathClone);
      GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone); 
      CopyFile(szPathOrig, szPathClone, FALSE);
 
      // Open the Clone using FILE_FLAG_DELETE_ON_CLOSE
      HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL,
                           OPEN_EXISTING,FILE_FLAG_DELETE_ON_CLOSE);
 
      // Start the Clone. Pass the PID and the fully qualified path
      // of the original file
      TCHAR szCmdLine[512];
      HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE,
                                        GetCurrentProcessId());
      wsprintf(szCmdLine, __TEXT("%s %d \"%s\""), szPathClone, 
               hProcessOrig, szPathOrig);
      STARTUPINFO si;
      ZeroMemory(&si, sizeof(si));
      si.cb = sizeof(si);
      PROCESS_INFORMATION pi;
      CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, 
                    NULL, NULL, &si, &pi);
      CloseHandle(hProcessOrig);
      CloseHandle(hfile);
 
      // now the original process may terminate
      } else {
 
      // Clone-EXE: Delete the  original EXE after termination
      HANDLE hProcessOrig = (HANDLE) _ttoi(__targv[1]);
      WaitForSingleObject(hProcessOrig, INFINITE);
      CloseHandle(hProcessOrig);
      DeleteFile(__targv[2]);
   }
   return(0);
}

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 20769209
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20769552
Note that the code jkr posted is the "DELETE_ON_CLOSE method" that was also explained on the site I posted. (Or in code selfdel01.c)
0

Featured Post

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

Question has a verified solution.

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

Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
Suggested Courses

589 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