|
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <ntsecapi.h>
#include "ntundoc.h"
// Forward declarations:
BOOL ListProcessThreads( DWORD dwOwnerPID );
BOOL EnableDebugPrivilege( BOOL Enable )
{
BOOL Success = FALSE;
HANDLE hToken = NULL;
do
{
if( !OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken ) )
{
printf("OpenProcessToken failed %d \n", GetLastError());
break;
}
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
if( !LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid ) )
{
printf("LookupPrivilegeValue failed %d \n", GetLastError());
break;
}
tp.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
if( !AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(tp), NULL, NULL ) )
{
printf("AdjusttokenPrivileges failed %d \n", GetLastError());
break;
}
Success = TRUE;
}
while( 0 );
if( hToken != NULL )
{
if( !CloseHandle( hToken ) )
printf("CloseHandle failed %d \n", GetLastError());
}
return Success;
}
typedef enum _THREADINFOCLASS {
ThreadBasicInformation,
ThreadTimes,
ThreadPriority,
ThreadBasePriority,
ThreadAffinityMask,
ThreadImpersonationToken,
ThreadDescriptorTableEntry,
ThreadEnableAlignmentFaultFixup,
ThreadEventPair_Reusable,
ThreadQuerySetWin32StartAddress,
ThreadZeroTlsCell,
ThreadPerformanceCount,
ThreadAmILastThread,
ThreadIdealProcessor,
ThreadPriorityBoost,
ThreadSetTlsArrayAddress,
ThreadIsIoPending,
ThreadHideFromDebugger,
MaxThreadInfoClass
} THREADINFOCLASS;
typedef NTSTATUS (WINAPI *QueryInformationThread)(
HANDLE ThreadHandle,
THREADINFOCLASS ThreadInformationClass,
PVOID ThreadInformation,
ULONG ThreadInformationLength,
PULONG ReturnLength
);
QueryInformationThread hProc;
void main( )
{
HMODULE hmod;
if(EnableDebugPrivilege( TRUE ) == FALSE )
{
printf("EnableDebugPrivilege failed %d \n", GetLastError());
return ;
}
hmod = LoadLibrary(L"ntdll.dll");
if(hmod != NULL)
{
hProc = (QueryInformationThread) GetProcAddress(hmod, "NtQueryInformationThread");
if(hProc == NULL)
{
printf("abbas %d \n", GetLastError());
}
}
ListProcessThreads(GetCurrentProcessId() );
getchar();
}
BOOL ListProcessThreads( DWORD dwOwnerPID )
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
HANDLE hthread;
CONTEXT context;
HANDLE hProcess;
LDT_ENTRY entry;
DWORD dwFsBase = 0;
DWORD read;
TEB teb;
DWORD a;
THREAD_BASIC_INFORMATION info;
PVOID threadinfo;
// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( hThreadSnap == INVALID_HANDLE_VALUE )
{
printf("error 1: %d \n", GetLastError());
return( FALSE );
}
// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32 );
// Retrieve information about the first thread,
// and exit if unsuccessful
if( !Thread32First( hThreadSnap, &te32 ) )
{
printf("error 2: %d \n", GetLastError()); // Show cause of failure
CloseHandle( hThreadSnap ); // Must clean up the
// snapshot object!
return( FALSE );
}
// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
//if( te32.th32OwnerProcessID == dwOwnerPID )
//{
// printf( "\n\n THREAD ID = 0x%08X",
// te32.th32ThreadID );
// printf( "\n base priority = %d", te32.tpBasePri );
// printf( "\n delta priority = %d", te32.tpDeltaPri );
//}
// printf("\n---- tid = %d, pid=%d ---- ", te32.th32ThreadID, te32.th32OwnerProcessID);
hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, te32.th32OwnerProcessID);
if(hthread && hProcess)
{
context.ContextFlags = CONTEXT_FULL | CONTEXT_ALL;
if(GetThreadContext(hthread, &context))
{
if( GetThreadSelectorEntry(hthread, context.SegFs, &entry))
{
dwFsBase = (entry.HighWord.Bits.BaseHi << 24) | (entry.HighWord.Bits.BaseMid << 16) | (entry.BaseLow) ;
printf("dwFsbase = %x .. .", dwFsBase);
__try {
if( ReadProcessMemory(hProcess, (LPCVOID)dwFsBase, (LPVOID)&teb, sizeof(TEB), &read) )
{
if( ReadProcessMemory( hProcess, teb.Win32ThreadInfo,
&threadinfo, sizeof( ULONG ), NULL))
{
printf("thread id = %d (%d) + win32threadinfo %x\n", te32.th32ThreadID, te32.th32OwnerProcessID, threadinfo);
}
else
{
printf("error in readprocessmemory %d \n", GetLastError());
}
}
else
{
printf("hproc is failed. %d and read = %d\n", GetLastError(), read);
}
} // try
__except (EXCEPTION_EXECUTE_HANDLER) {
printf("exception occured.\n");
}
} // getthreadselectorentry
else
{
printf("getthreaselectorentry failed. %d \n", GetLastError());
}
}
else
{
printf("error 4: %d \n", GetLastError());
}
}
else
{
printf("error 3: %d \n", GetLastError());
}
} while( Thread32Next(hThreadSnap, &te32 ) );
// Don't forget to clean up the snapshot object.
CloseHandle( hThreadSnap );
return( TRUE );
}
Himanshu Pareek
India
|
|
|
|
|
|
|
Hello Sir,
I read your article. Really it's very great article.
ThanksIf you can think then I Can.
|
|
|
|
|
|
You can use this to clean up after a program runs but if the user wants to hack into your program you probably want to wait until your program terminates and then overwrite the file before deleting it so they can't undelete the file and examine it.
|
|
|
|
|
Yes, I agree. If security is important then it would make sense to wipe the file clean before deleting it.
|
|
|
|
|
I just question how portable it is to future versions of Windows, and does this still work in Win64?
I've used the batch file technique described here:
http://www.codeproject.com/KB/files/cpselfdestruct2.aspx
It writes out a temporary batch file, which loops until it can delete the .exe (which it can after the .exe ends) and then the batch file deletes itself (which Windows does allow).
But I find the article interesting, to see how you made your method work.
|
|
|
|
|
I know the technique works as long as the process that is attempting to self-delete is a 32-bit process. It doesn't seem to matter whether the OS on which you're running the executable is 32-bit or not. In fact, now that I think about it, when I ran this on the 64-bit version of Windows 7, it actually worked even though the process that it was injecting the code into - explorer.exe - was a 64-bit process. Hmm. That doesn't seem right. Guess I'll have to go home and check it out in the evening.
But yeah, more than the functional aspect of what this program does (in that it self-deletes) what I thought was interesting was the idea that one can toy as one wills with another process! :P
|
|
|
|
|
Is there any way to create a self-deleting executable in Windows CE?
|
|
|
|
|
I am fairly confident that one can come up with a self-deleting executable on CE. Now, will the technique described in this article work as-is? I don't know, but I'd be surprised if it did!
|
|
|
|
|
Not to rain on the parade, but why create an empty process for this when you have so many already running processes (such as explorer.exe) to do it for you? (And yes, it does work and is used by more than one commercial "no-footprint" product I have written.)
1. VirtualAllocEx, allocate memory in the target process
2. Create your code. I'll not give away the details about how to do this well, you can figure it out or use my library when I release it. Your code should:
a. Wait on the handle to your process (use DuplicateHandle to pass it through, or open it in the remote)
b. When the process exits, Run your DeleteFile code
c. Clean itself up. e.g. VirtualFree and exit the thread
3. Copy your code into the target with WriteProcessMemory
4. CreateRemoteThread to execute it.
That has a much lower overhead than creating and maiming a process.
|
|
|
|
|
Yes, the technique as you describe it certainly does sound like a much better way. The original technique as described on the catch22[^] site seeks to come up with a solution that has a good chance of working correctly on all variants of Windows all the way from 95! CreateRemoteThread for instance, is only available on Windows 2000 and later.
But then, this benefit is certainly moot now given that almost nobody uses Windows 95 or 98 these days.
|
|
|
|
|
Do you have any estimate as to when you'll post your version? Perhaps you can also add the file overwrite before delete feature when you do?
|
|
|
|
|
I try to embed your code into my project on VC8. And have compile error:
c:\program files\microsoft sdks\windows\v6.0a\include\devicetopology.h(457) : error C2365: 'Network' : redefinition; previous definition was 'enumerator'
C:\Program Files\Microsoft SDKs\Windows\v6.0A\\include\ntsecapi.h(832) : see declaration of 'Network'
It shows me next code in :
enum __MIDL___MIDL_itf_devicetopology_0000_0000_0013
{ Unknown_Connector = 0,
Physical_Internal = ( Unknown_Connector + 1 ) ,
Physical_External = ( Physical_Internal + 1 ) ,
Software_IO = ( Physical_External + 1 ) ,
Software_Fixed = ( Software_IO + 1 ) ,
Network = ( Software_Fixed + 1 )
>>> } ConnectorType;
|
|
|
|
|
Thanx for a very useful & interesting article. Special regards for explaining all the stuff so thoroughly.
Just a couple of questions:
did you use asm for message boxes to get the code clean and minimize shellcode? is it possible to use C to call those functions instead of asm?
and could I declare some other functions in SELFDEL struct, for example to make the executable not selfdelete but write something inside itself?
|
|
|
|
|
hey ctapyllika,
thanks!
yes, i did indeed write the code for showing the message box in assembly so that, it is as you said - clean and minimal.. but you can certainly use C to call those functions.. and finally, yes, you can write any code you like because the shellcode is written over the entrypoint of the remote process and the Win32 environment should have been suitably initialized by then allowing you to call any api..
hope this helps!
--
gleat
http://blogorama.nerdworks.in[ ^]
-- Number Two's eyes narrowed and became what are known in the Shouting and Killing People trade as cold slits, the idea presumably being to give your opponent the impression that you have lost your glasses or are having difficulty keeping awake. Why this is frightening is an, as yet, unresolved problem. -- HHGTG
|
|
|
|
|
hi,
this one is good when this excute as a only give code . when i attach this code to MFC appliucation compiler display error msg
1)error C2197: 'int (__stdcall *)(void)' : too many actual parameter
please tell me what is issue with this code .if any body knows plz reply me.
Thank you
Hi manish Here.
|
|
|
|
|
hi,
this one is good when this excute as a only give code . when i attach this code to MFC appliucation compiler display error msg
1)error C2197: 'int (__stdcall *)(void)' : too many actual parameter
please tell me what is issue with this code .if any body knows plz reply me.
Thank you
Hi manish Here.
|
|
|
|
|
such as a wrapper/object component to be included styled for .net?
I just don't have the time to learn C++ well enough, or to relearn assembly again to handle all this. seems to me there out to be a wrapable system and all. any ideas, or maybe a way to make a virtually code executed .net delegate to delete with?
|
|
|
|
|
Hey,
If you want to write self-deleting executables using .NET then you're probably safer off sticking to the FILE_FLAG_DELETE_ON_CLOSE flag using p-invoke. If you want to inject code into remote processes then that's really stretching things a bit with .NET though I am sure that it could be done.
--
gleat
http://blogorama.nerdworks.in[ ^]
-- Number Two's eyes narrowed and became what are known in the Shouting and Killing People trade as cold slits, the idea presumably being to give your opponent the impression that you have lost your glasses or are having difficulty keeping awake. Why this is frightening is an, as yet, unresolved problem. -- HHGTG
|
|
|
|
|
Hi, this is a good topic for me.
I've tried to add this function into my dialog-based application, but it didn't work.
I complied the project with Visual Studio 2005 but it showed me an error message,
----------------------------------------------------------------------------------------------
Error 1 fatal error C1853: 'Debug\Test.pch' precompiled header file is from a previous version of the compiler, or the precompiled header is C++ and you are using it from C (or vice versa) d:\test\selfdel.c 17
----------------------------------------------------------------------------------------------
How to add this function to dialog-base MFC Application?
Thank you.
|
|
|
|
|
You might want to try excluding the 'C' file from using precompiled headers in VS. You can do that by going to the properties dialog for that file (right-click on the file in solution explorer and select "Properties") and altering the value for the "Create/Use Precompiled Header" setting under the section called "Precompiled Headers" categorized under "C/C++". Try selecting "Not Using Precompiled Headers".
|
|
|
|
|
How could I remove the message box of hijacked entry point
|
|
|
|
|
Hey,
Sorry about the delay in replying. To get rid of the message box first modify "remote_thread" to look like this:
<br />
void remote_thread()<br />
{<br />
SELFDEL *remote = (SELFDEL *)0xFFFFFFFF;<br />
<br />
FARPROC pfnLoadLibrary = remote->fnLoadLibrary;<br />
FARPROC pfnGetProcAddress = remote->fnGetProcAddress;<br />
FARPROC pfnMessageBox;<br />
<br />
remote->fnWaitForSingleObject(remote->hParent, INFINITE);<br />
remote->fnCloseHandle(remote->hParent);<br />
<br />
while(!remote->fnDeleteFile(remote->szFileName))<br />
{<br />
remote->fnSleep(1000);<br />
}<br />
<br />
remote->fnExitProcess(0);<br />
}<br />
Then change the shellcode to look like this:
<br />
char shellcode[] = {<br />
'\x55', '\x8B', '\xEC', '\x83', '\xEC', '\x10',<br />
'\xC7', '\x45', '\xF0', '\xFF', '\xFF', '\xFF',<br />
'\xFF', '\x8B', '\x45', '\xF0', '\x8B', '\x48',<br />
'\x20', '\x89', '\x4D', '\xF4', '\x8B', '\x55',<br />
'\xF0', '\x8B', '\x42', '\x24', '\x89', '\x45',<br />
'\xFC', '\x6A', '\xFF', '\x8B', '\x4D', '\xF0',<br />
'\x8B', '\x11', '\x52', '\x8B', '\x45', '\xF0',<br />
'\x8B', '\x48', '\x04', '\xFF', '\xD1', '\x8B',<br />
'\x55', '\xF0', '\x8B', '\x02', '\x50', '\x8B',<br />
'\x4D', '\xF0', '\x8B', '\x51', '\x08', '\xFF',<br />
'\xD2', '\x8B', '\x45', '\xF0', '\x83', '\xC0',<br />
'\x2C', '\x50', '\x8B', '\x4D', '\xF0', '\x8B',<br />
'\x51', '\x0C', '\xFF', '\xD2', '\x85', '\xC0',<br />
'\x75', '\x0F', '\x68', '\xE8', '\x03', '\x00',<br />
'\x00', '\x8B', '\x45', '\xF0', '\x8B', '\x48',<br />
'\x10', '\xFF', '\xD1', '\xEB', '\xDE', '\x6A',<br />
'\x00', '\x8B', '\x55', '\xF0', '\x8B', '\x42',<br />
'\x14', '\xFF', '\xD0', '\x8B', '\xE5', '\x5D',<br />
'\xC3'<br />
};<br />
And finally, change the code for initializing the shellcode with the actual address to the data to look like this:
<br />
data = process_entry + sizeof( shellcode );<br />
shellcode[12] = (char)( data >> 24 );<br />
shellcode[11] = (char)( ( data >> 16 ) & 0xFF );<br />
shellcode[10] = (char)( ( data >> 8 ) & 0xFF );<br />
shellcode[9] = (char)( data & 0xFF );<br />
That's it!
|
|
|
|
|