HomeCXO'sIT ManagersIT Developers

0 Login
0 Register
0 Forgot Password
0 Reload This Question
0 Delphi Area
0 Send To A Friend
0 Ask Your Question

Home All Topics Programming Languages Delphi Viewing a Question

From: menorcanet
Date: 07/22/1999 06:50PM PST
Answer Grade: A
Points: 50
ok, I want to completely hide my program.. that means..
17 Hide it from the task bar
27 Hide it from ctrl+alt+del
37 Hide it from programs such as Wintop
47 Hide it also when it's ran as a service
57 If it uses TServerSocket, the connection made by my program must not be shown with NETSTAT or any of those commands that show the current internet connections.
EE is totally Free & Sign-up is quick and easy
Member Name (can not be changed)
Email (requires verification)
Password

Confirm Password
Receive our Monthly Newsletter
I agree to the Member Agreement

View Accepted Answer

Question History
Rejected Answer from viktornet 07/22/1999 06:57PM PST
here... hiding from taskbar...

ShowWindow(Application.Handle, SW_HIDE);

for tht ctrl-del-alt thingy here is the code...

Const RSP_SIMPLE_SERVICE = 1;
Const RSP_UNREGISTER_SERVICE = 0;

//hide
RegisterServiceProcess(GetCurrentProcessId, RSP_SIMPLE_SERVICE);
//show
RegisterServiceProcess(GetCurrentProcessId, RSP_UNREGISTER_SERVICE);

this should be able to hide your application completely.... try it out...

..-=ViKtOr=-..
Comment from Gwena 07/22/1999 07:02PM PST
Hmmmm ;-)

So you need a program that nobody can tell is running
And it is running a server on the net.....Hmmmmm
Sounds like a recipe for a back-orifice clone of some sort...
psssssst.....What R U up to anyway?  (I can keep a secret)

;-)


Comment from inthe 07/22/1999 07:23PM PST
how that gonna stop wintop or netstat?
hungry for 500 points i think :-)
Comment from viktornet 07/22/1999 07:28PM PST
menorcaret, please REJECT my answer...

i'm otta here....
Comment from Gwena 07/22/1999 07:38PM PST
Hmmmm ;-)

So you need a program that nobody can tell is running
And it is running a server on the net.....Hmmmmm
Sounds like a recipe for a back-orifice clone of some sort...
psssssst.....What R U up to anyway?  (I can keep a secret)

;-)


Comment from inthe 07/22/1999 07:47PM PST
>>menorcaret, please REJECT my answer...
why ?? you deserve some points for answereing 2 of the 5.
i think the other 3 may not be possible anyway.

>>47 Hide it also when it's ran as a service
well WHEN you do this as viktor correctly did:
Const RSP_UNREGISTER_SERVICE = 0;
//hide
RegisterServiceProcess(GetCurrentProcessId, RSP_SIMPLE_SERVICE);
for the reason of hiding a app by telling windows its a service.so the answer to q2 and q4 conflict with each other.

>>how that gonna stop wintop or netstat?
id seriously doubt thats possible i was just kidding around....
id say dont reject viks answer just wait to see if anyone else can do more than 2.
(may be a long wait though)

Comment from viktornet 07/22/1999 07:50PM PST
>>why ??
to make you happy...
Comment from inthe 07/22/1999 07:53PM PST
sh*t mate just ignore me im just jealous of 500 points for easy(ish)  question ;-)
Comment from viktornet 07/22/1999 08:01PM PST
i'm too damn sick of this shit... i prefer the answer to be rejected than someone being jealous of the 500 (easy???) points...
Comment from Madshi 07/22/1999 11:17PM PST
Hi guys, it *IS* possible to hide your program from WinTop. But I don't know about NetStat.

Download the sources from BackOrifice2000 here:
http://www.bo2k.com

In the unit "process_hop.cpp" you'll find everything you need to hide your program from WinTop. Though - you surely have noticed - these are C++ sources. Much fun with converting the sources...   :-)

Regards, Madshi.
Comment from simonet 07/23/1999 12:02AM PST
Hi Madshi!

>Much fun with converting the sources...   :-)

Anything can be done given enough time.
Given enough time, nothing has to be done anymore!

Alex
Comment from Madshi 07/23/1999 12:24AM PST
:-)
Comment from menorcanet 07/23/1999 05:06AM PST
""RegisterServiceProcess(GetCurrentProcessId, RSP_SIMPLE_SERVICE); ""

delphi says: undeclared indentifier: RegisterSerViceProcess


>Hmmmm ;-)

>So you need a program that nobody can tell is running
>And it is running a server on the net.....Hmmmmm
>Sounds like a recipe for a back-orifice clone of some >sort...
>psssssst.....What R U up to anyway?  (I can keep a secret)

>;-)

just that I'd like to able to do so..

>menorcaret, please REJECT my answer...
>i'm otta here....

ok

I won't give 500 points for only some parts..
but maybe I'll increase the points if I can get the full solution, or I could delete this and post some q. for each of who gives me a part to have a part of the points..

I'll accept the answer with an A.


I'm gonna check that about bk2000.. will be back :)


Comment from Epsylon 07/23/1999 09:33AM PST
Madshi, there are no sources available right now. Do you have them?
Comment from Madshi 07/23/1999 10:00AM PST
Hi Eps, I think this one should work:

http://www.bo2k.com/warez/bo2ksrc.zip

Regards, Madshi.
Comment from menorcanet 07/23/1999 10:08AM PST
checked the source.. too difficult for me.. :(
Comment from Madshi 07/23/1999 10:32AM PST
It *IS* difficult...   :-/

Do you need this stuff for win9x or for winNt or for both?
Comment from menorcanet 07/23/1999 12:43PM PST
should work on both
Comment from inthe 07/23/1999 02:20PM PST
>>undeclared indentifier: RegisterSerViceProcess

you need to write the function first put this after the {$R *.DFM} line:

function  RegisterServiceProcess(dwProcessID,dwType : DWORD) : DWORD; stdcall; external 'KERNEL32.DLL';

Comment from viktornet 07/23/1999 05:15PM PST
the code in that source code isn't that hard... as a matter of fact, it's pretty basic... go check the source codes in sysinternals.com or whatever it was.... then you will see what IS dificult :) hehe.. lotsa tricks are used in the source codes of sysinternals.com.. they guyz are prolly some M$ workers and know all about Windows and shit :)))
Comment from bryan7 07/25/1999 01:30PM PST
well. someone could translate that C code to delphi ?
Comment from menorcanet 07/25/1999 01:48PM PST
ouch, didn't realise I was using my job acount..

so.. noone wants 2000 points ?
Comment from Madshi 07/25/1999 02:05PM PST
Of course I would like to get 2000 points. But I've not the time to translate ALL that stuff to Delphi! The win9x part is not too difficult, I think. But the NT part is tricky, don't know if you can simply copy Delphi programs into a new thread in another process. I would have to do several tests, and I've not enough time for that...   :-(
Comment from menorcanet 07/25/1999 02:53PM PST
well.. then just for Win9x..
Comment from Madshi 07/25/1999 11:19PM PST
Ok, I'll do it, but you will have to wait till next weekend...
Comment from Jaymol 07/26/1999 06:29AM PST
You want to hide your program COMPLETELY from Windows NT?
Comment from chengjian 07/26/1999 07:52AM PST
It's a good question, but seems imposible:-(
I think if it spend 500 on a registerservice, it's too expensive:-)
Comment from menorcanet 07/26/1999 09:57AM PST
ok, I'll wait.. I don't hurry for this... I don't need it now
Comment from Jaymol 07/28/1999 08:03AM PST
I know how it is done though...
Accepted Answer from Madshi 07/28/1999 10:36AM PST
Hi guys,

well, here comes the win9x solution. It compiles&runs fine with D3&D4. Don't know about D2.
Two notes:
(1) This code does only effect programs that were started AFTER you called "HookToolhelp". You should also call RegisterServiceProcess to complete the hiding.
(2) You MUST NOT close your program without rebooting Windows!! Otherwise all of the programs that were started after you called "HookToolhelp" will crash as soon as they call one of the toolhelp functions.

The code is a simple translation of a part of this code:

http://www.bo2k.com/warez/bo2ksrc.zip

Simply create a new application, drop two buttons on the form, name the first one "HideMe" and the second one "ShowMe". Then connect the event handlers of the two buttons.

Hmmmm... You talked about 2000 points for a complete solution. So this should be worth 1000 points, right!?   :-))
And if you like this code, I would be glad about an A grade...   :-))

Regards, Madshi.

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   Button2: TButton;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
 private
   { Private-Deklarationen }
 public
   { Public-Deklarationen }
 end;

var
 Form1: TForm1;

implementation

{$R *.DFM}

const CENEWHDR = $003C;          // offset of new EXE header
     CEMAGIC  = $5A4D;          // old EXE magic id:  'MZ'
     CPEMAGIC = $4550;          // NT portable executable
type  TImageExportDirectory  = packed record
                                Characteristics       : dword;
                                TimeDateStamp         : dword;
                                MajorVersion          : word;
                                MinorVersion          : word;
                                Name                  : dword;
                                Base                  : dword;
                                NumberOfFunctions     : dword;
                                NumberOfNames         : dword;
                                AddressOfFunctions    : cardinal;
                                AddressOfNames        : cardinal;
                                AddressOfNameOrdinals : cardinal;
                              end;
     TPImageExportDirectory = ^TImageExportDirectory;

type  TPWord                 = ^word;
     TAWord                 = array [0..maxInt shr 1-1] of word;
     TPAWord                = ^TAWord;
     TACardinal             = array [0..maxInt shr 2-1] of cardinal;
     TPACardinal            = ^TACardinal;
     TAInteger              = array [0..maxInt shr 2-1] of integer;
     TPAInteger             = ^TAInteger;

function GetModuleNtHeaders(module: cardinal) : PImageNtHeaders;
begin
 result:=nil;
 try
   if TPWord(module)^<>CEMAGIC then exit;
   result:=pointer(module+TPWord(module+CENEWHDR)^);
   if result^.signature<>CPEMAGIC then result:=nil;
 except result:=nil; end;
end;

function GetModuleExportDirectory(module: cardinal) : TPImageExportDirectory;
begin
 result:=nil;
 try
   result:=pointer(module+GetModuleNtHeaders(module)^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
 except end;
end;

function GetProcAddress_(module: cardinal; ord: cardinal) : pointer;
var exp : TPImageExportDirectory;
begin
 result:=nil;
 try
   exp:=GetModuleExportDirectory(module);
   if exp<>nil then
     with exp^ do
       if ord<NumberOfFunctions then
         result:=pointer(module+TPACardinal(module+AddressOfFunctions)^[ord]);
 except end;
end;

function SetProcAddress(module: cardinal; procName: string; newAdr: pointer) : boolean;
var exp : TPImageExportDirectory;
   i1  : integer;
begin
 result:=false;
 try
   exp:=GetModuleExportDirectory(module);
   if exp<>nil then
     with exp^ do
       for i1:=0 to NumberOfNames-1 do
         if pchar(module+TPACardinal(module+exp.AddressOfNames)^[i1])=procName then begin
           TPAInteger(module+AddressOfFunctions)^[TPAWord(module+exp.AddressOfNameOrdinals)^[i1]]:=integer(newAdr)-integer(module);
           result:=true;
           break;
         end;
 except end;
end;

function UnprotectExportTable(module: cardinal) : boolean;
var exp     : TPImageExportDirectory;
   size    : cardinal;
   fa      : cardinal;  // firstAddress
   fp,np   : cardinal;  // firstPage / numPages
   vxdcall : pointer;
begin
 result:=false;
 try
   // Check for kernel32.dll export table
   size:=GetModuleNtHeaders(module)^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
   if size=0 then exit;
   // Good, we have an export table. Lets get it.
   exp:=GetModuleExportDirectory(module);
   // Change protection on kernel32.dll export table (make writable)
   // (can't use "VirtualProtect")
   fa:=module+exp^.AddressOfFunctions;
   fp:=fa div 4096;
   np:=(((fa mod 4096 + exp^.NumberOfFunctions)*4)+4095) div 4096;
   dec(fa,fa mod 4096);
   result:=not IsBadWritePtr(pointer(fa),np*4096);
   if not result then begin
     // Get undocumented VxDCall procedure
     vxdcall:=GetProcAddress_(GetModuleHandle(kernel32),1);
     if @vxdcall=nil then exit;
     asm
       push 020060000h           // PC_WRITEABLE | PC_USER | PC_STATIC
       push 0FFFFFFFFh           // Keep all previous bits
       push dword ptr [np]       // dword ptr [mbi+0Ch] # of pages
       push dword ptr [fp]       // dword ptr [ped] page #
       push 1000Dh               // _PageModifyPermissions (win32_service_table #)
       call dword ptr [vxdcall]  // VxDCall0
     end;
     result:=not IsBadWritePtr(pointer(fa),np*4096);
   end;
 except end;
end;

const MAX_MODULE_NAME32 = 255;
type TProcessEntry32 = record
                        dwSize              : DWORD;
                        cntUsage            : DWORD;
                        th32ProcessID       : DWORD;       // this process
                        th32DefaultHeapID   : DWORD;
                        th32ModuleID        : DWORD;       // associated exe
                        cntThreads          : DWORD;
                        th32ParentProcessID : DWORD;        // this process's parent process
                        pcPriClassBase      : integer;      // Base priority of process's threads
                        dwFlags             : DWORD;
                        szExeFile           : array [0..MAX_PATH-1] of char;    // Path
                      end;
    TThreadEntry32  = record
                        dwSize              : DWORD;
                        cntUsage            : DWORD;
                        th32ThreadID        : DWORD;       // this thread
                        th32OwnerProcessID  : DWORD;        // Process this thread is associated with
                        tpBasePri           : integer;
                        tpDeltaPri          : integer;
                        dwFlags             : DWORD;
                      end;
    TModuleEntry32  = record
                        dwSize              : DWORD;
                        th32ModuleID        : DWORD;        // This module
                        th32ProcessID       : DWORD;        // owning process
                        GlblcntUsage        : DWORD;        // Global usage count on the module
                        ProccntUsage        : DWORD;        // Module usage count in th32ProcessID's context
                        modBaseAddr         : pointer;      // Base address of module in th32ProcessID's context
                        modBaseSize         : DWORD;        // Size in bytes of module starting at modBaseAddr
                        hModule             : HMODULE;      // The hModule of this module in th32ProcessID's context
                        szModule            : array [0..MAX_MODULE_NAME32] of char;
                        szExePath           : array [0..MAX_PATH-1] of char;
                      end;

type TProcessWalk = function (snapshotHandle: cardinal; var pe32: TProcessEntry32) : bool; stdcall;
    TThreadWalk  = function (snapshotHandle: cardinal; var te32:  TThreadEntry32) : bool; stdcall;
    TModuleWalk  = function (snapshotHandle: cardinal; var me32:  TModuleEntry32) : bool; stdcall;

function HookedProcess32First(snapshotHandle: cardinal; var pe32: TProcessEntry32) : bool; stdcall;
begin
 result:=TProcessWalk($22222222)(snapshotHandle,pe32);
 if not result then exit;
 while pe32.th32ProcessID=$11111111 do begin
   result:=TProcessWalk($33333333)(snapshotHandle,pe32);
   if not result then exit;
 end;
 result:=true;
end;

function HookedProcess32Next(snapshotHandle: cardinal; var pe32: TProcessEntry32) : bool; stdcall;
begin
 repeat
   result:=TProcessWalk($33333333)(snapshotHandle,pe32);
   if not result then exit;
 until pe32.th32ProcessID<>$11111111;
 result:=true;
end;

function HookedThread32First(snapshotHandle: cardinal; var te32: TThreadEntry32) : bool; stdcall;
begin
 result:=TThreadWalk($44444444)(snapshotHandle,te32);
 if not result then exit;
 while te32.th32OwnerProcessID=$11111111 do begin
   result:=TThreadWalk($55555555)(snapshotHandle,te32);
   if not result then exit;
 end;
 result:=true;
end;

function HookedThread32Next(snapshotHandle: cardinal; var te32: TThreadEntry32) : bool; stdcall;
begin
 repeat
   result:=TThreadWalk($55555555)(snapshotHandle,te32);
   if not result then exit;
 until te32.th32OwnerProcessID<>$11111111;
 result:=true;
end;

function HookedModule32First(snapshotHandle: cardinal; var me32: TModuleEntry32) : bool; stdcall;
begin
 result:=TModuleWalk($66666666)(snapshotHandle,me32);
 if not result then exit;
 while me32.th32ProcessID=$11111111 do begin
   result:=TModuleWalk($77777777)(snapshotHandle,me32);
   if not result then exit;
 end;
 result:=true;
end;

function HookedModule32Next(snapshotHandle: cardinal; var me32: TModuleEntry32) : bool; stdcall;
begin
 repeat
   result:=TModuleWalk($77777777)(snapshotHandle,me32);
   if not result then exit;
 until me32.th32ProcessID<>$11111111;
 result:=true;
end;

procedure HookToolhelpEnd; begin end;

var oldAdr   : array [0..5] of pointer = (nil,nil,nil,nil,nil,nil);
   hookCode : pointer                 = nil;

function HookToolhelp : boolean;
var dll     : cardinal;
   cs      : cardinal;  // codeSize
   pid     : cardinal;
   i1      : integer;
   pc      : ^cardinal;
begin
 result:=false;
 try
   dll:=GetModuleHandle(kernel32);
   if not UnprotectExportTable(dll) then exit;
   // Get shared memory
   cs:=cardinal(@HookToolhelpEnd)-cardinal(@HookedProcess32First);
   if hookCode=nil then
     hookCode:=VirtualAlloc(pointer($9CDC0000),cs,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE);
   if hookCode=nil then exit;
   hookCode:=pointer($9CDC0000);
   // Copy code into shared memory
   Move(pointer(@HookedProcess32First)^,hookCode^,cs);
   // Store procedure addresses
   pid:=GetCurrentProcessId;
   oldAdr[0]:=GetProcAddress(dll,'Process32First');
   oldAdr[1]:=GetProcAddress(dll,'Process32Next' );
   oldAdr[2]:=GetProcAddress(dll,'Thread32First' );
   oldAdr[3]:=GetProcAddress(dll,'Thread32Next'  );
   oldAdr[4]:=GetProcAddress(dll,'Module32First' );
   oldAdr[5]:=GetProcAddress(dll,'Module32Next'  );
   // Modify code to correct addresses
   for i1:=0 to cs-5 do begin
     pc:=pointer(integer(hookCode)+i1);
     case pc^ of
       $11111111 : pc^:=pid;
       $22222222 : pc^:=cardinal(oldAdr[0]);
       $33333333 : pc^:=cardinal(oldAdr[1]);
       $44444444 : pc^:=cardinal(oldAdr[2]);
       $55555555 : pc^:=cardinal(oldAdr[3]);
       $66666666 : pc^:=cardinal(oldAdr[4]);
       $77777777 : pc^:=cardinal(oldAdr[5]);
     end;
   end;
   // Now we modify the export table to point to our replacement code
   SetProcAddress(dll,'Process32First',hookCode);
   SetProcAddress(dll,'Process32Next', pointer(integer(hookCode)+integer(@HookedProcess32Next)-integer(@HookedProcess32First)));
   SetProcAddress(dll,'Thread32First', pointer(integer(hookCode)+integer(@HookedThread32First)-integer(@HookedProcess32First)));
   SetProcAddress(dll,'Thread32Next',  pointer(integer(hookCode)+integer(@HookedThread32Next )-integer(@HookedProcess32First)));
   SetProcAddress(dll,'Module32First', pointer(integer(hookCode)+integer(@HookedModule32First)-integer(@HookedProcess32First)));
   SetProcAddress(dll,'Module32Next',  pointer(integer(hookCode)+integer(@HookedModule32Next )-integer(@HookedProcess32First)));
   result:=true;
 except end;
end;

function UnhookToolhelp : boolean;
var dll : cardinal;
begin
 result:=false;
 try
   dll:=GetModuleHandle(kernel32);
   SetProcAddress(dll,'Process32First',oldAdr[0]);
   SetProcAddress(dll,'Process32Next', oldAdr[1]);
   SetProcAddress(dll,'Thread32First', oldAdr[2]);
   SetProcAddress(dll,'Thread32Next',  oldAdr[3]);
   SetProcAddress(dll,'Module32First', oldAdr[4]);
   SetProcAddress(dll,'Module32Next',  oldAdr[5]);
   result:=true;
 except end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 HookToolhelp;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 UnhookToolhelp;
end;

end.

Comment from menorcanet 07/28/1999 01:57PM PST
Hi.. I'll check it now..

"
Hmmmm... You talked about 2000 points for a complete solution. So this should be worth 1000 points, right!?   :-))
And if you like this code, I would be glad about an A grade...   :-))
"

well.. 2000 ... I meant I would give an A grade.. 500x4 ..
I don't have 2000 points.. ;)

Comment from Madshi 07/28/1999 10:06PM PST
Ahh...  :-)  Ok, no prob...  :-)
Comment from menorcanet 07/29/1999 09:37AM PST
hmm.. please check what I'm doing wrong.. it's still visible to wintop..


unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   Button2: TButton;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
   procedure FormCreate(Sender: TObject);
 private
   { Private-Deklarationen }
 public
   { Public-Deklarationen }
 end;

var
 Form1: TForm1;

implementation

{$R *.DFM}

Const RSP_SIMPLE_SERVICE = 1;
Const RSP_UNREGISTER_SERVICE = 0;

const CENEWHDR = $003C;          // offset of new EXE header
     CEMAGIC  = $5A4D;          // old EXE magic id:  'MZ'
     CPEMAGIC = $4550;          // NT portable executable
type  TImageExportDirectory  = packed record
                                Characteristics       : dword;
                                TimeDateStamp         : dword;
                                MajorVersion          : word;
                                MinorVersion          : word;
                                Name                  : dword;
                                Base                  : dword;
                                NumberOfFunctions     : dword;
                                NumberOfNames         : dword;
                                AddressOfFunctions    : cardinal;
                                AddressOfNames        : cardinal;
                                AddressOfNameOrdinals : cardinal;
                              end;
     TPImageExportDirectory = ^TImageExportDirectory;

type  TPWord                 = ^word;
     TAWord                 = array [0..maxInt shr 1-1] of word;
     TPAWord                = ^TAWord;
     TACardinal             = array [0..maxInt shr 2-1] of cardinal;
     TPACardinal            = ^TACardinal;
     TAInteger              = array [0..maxInt shr 2-1] of integer;
     TPAInteger             = ^TAInteger;

function  RegisterServiceProcess(dwProcessID,dwType : DWORD) : DWORD; stdcall; external 'KERNEL32.DLL';

function GetModuleNtHeaders(module: cardinal) : PImageNtHeaders;
begin
 result:=nil;
 try
   if TPWord(module)^<>CEMAGIC then exit;
   result:=pointer(module+TPWord(module+CENEWHDR)^);
   if result^.signature<>CPEMAGIC then result:=nil;
 except result:=nil; end;
end;

function GetModuleExportDirectory(module: cardinal) : TPImageExportDirectory;
begin
 result:=nil;
 try
   result:=pointer(module+GetModuleNtHeaders(module)^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
 except end;
end;

function GetProcAddress_(module: cardinal; ord: cardinal) : pointer;
var exp : TPImageExportDirectory;
begin
 result:=nil;
 try
   exp:=GetModuleExportDirectory(module);
   if exp<>nil then
     with exp^ do
       if ord<NumberOfFunctions then
         result:=pointer(module+TPACardinal(module+AddressOfFunctions)^[ord]);
 except end;
end;

function SetProcAddress(module: cardinal; procName: string; newAdr: pointer) : boolean;
var exp : TPImageExportDirectory;
   i1  : integer;
begin
 result:=false;
 try
   exp:=GetModuleExportDirectory(module);
   if exp<>nil then
     with exp^ do
       for i1:=0 to NumberOfNames-1 do
         if pchar(module+TPACardinal(module+exp.AddressOfNames)^[i1])=procName then begin
           TPAInteger(module+AddressOfFunctions)^[TPAWord(module+exp.AddressOfNameOrdinals)^[i1]]:=integer(newAdr)-integer(module);
           result:=true;
           break;
         end;
 except end;
end;

function UnprotectExportTable(module: cardinal) : boolean;
var exp     : TPImageExportDirectory;
   size    : cardinal;
   fa      : cardinal;  // firstAddress
   fp,np   : cardinal;  // firstPage / numPages
   vxdcall : pointer;
begin
 result:=false;
 try
   // Check for kernel32.dll export table
   size:=GetModuleNtHeaders(module)^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
   if size=0 then exit;
   // Good, we have an export table. Lets get it.
   exp:=GetModuleExportDirectory(module);
   // Change protection on kernel32.dll export table (make writable)
   // (can't use "VirtualProtect")
   fa:=module+exp^.AddressOfFunctions;
   fp:=fa div 4096;
   np:=(((fa mod 4096 + exp^.NumberOfFunctions)*4)+4095) div 4096;
   dec(fa,fa mod 4096);
   result:=not IsBadWritePtr(pointer(fa),np*4096);
   if not result then begin
     // Get undocumented VxDCall procedure
     vxdcall:=GetProcAddress_(GetModuleHandle(kernel32),1);
     if @vxdcall=nil then exit;
     asm
       push 020060000h           // PC_WRITEABLE | PC_USER | PC_STATIC
       push 0FFFFFFFFh           // Keep all previous bits
       push dword ptr [np]       // dword ptr [mbi+0Ch] # of pages
       push dword ptr [fp]       // dword ptr [ped] page #
       push 1000Dh               // _PageModifyPermissions (win32_service_table #)
       call dword ptr [vxdcall]  // VxDCall0
     end;
     result:=not IsBadWritePtr(pointer(fa),np*4096);
   end;
 except end;
end;

const MAX_MODULE_NAME32 = 255;
type TProcessEntry32 = record
                        dwSize              : DWORD;
                        cntUsage            : DWORD;
                        th32ProcessID       : DWORD;   // this process
                        th32DefaultHeapID   : DWORD;
                        th32ModuleID        : DWORD;   // associated exe
                        cntThreads          : DWORD;
                        th32ParentProcessID : DWORD;        // this process's parent process
                        pcPriClassBase      : integer;      // Base priority of process's threads
                        dwFlags             : DWORD;
                        szExeFile           : array [0..MAX_PATH-1] of char;    // Path
                      end;
    TThreadEntry32  = record
                        dwSize              : DWORD;
                        cntUsage            : DWORD;
                        th32ThreadID        : DWORD;   // this thread
                        th32OwnerProcessID  : DWORD;        // Process this thread is associated with
                        tpBasePri           : integer;
                        tpDeltaPri          : integer;
                        dwFlags             : DWORD;
                      end;
    TModuleEntry32  = record
                        dwSize              : DWORD;
                        th32ModuleID        : DWORD;        // This module
                        th32ProcessID       : DWORD;        // owning process
                        GlblcntUsage        : DWORD;        // Global usage count on the module
                        ProccntUsage        : DWORD;        // Module usage count in th32ProcessID's context
                        modBaseAddr         : pointer;      // Base address of module in th32ProcessID's context
                        modBaseSize         : DWORD;        // Size in bytes of module starting at modBaseAddr
                        hModule             : HMODULE;      // The hModule of this module in th32ProcessID's context
                        szModule            : array [0..MAX_MODULE_NAME32] of char;
                        szExePath           : array [0..MAX_PATH-1] of char;
                      end;

type TProcessWalk = function (snapshotHandle: cardinal; var pe32: TProcessEntry32) : bool; stdcall;
    TThreadWalk  = function (snapshotHandle: cardinal; var te32:  TThreadEntry32) : bool; stdcall;
    TModuleWalk  = function (snapshotHandle: cardinal; var me32:  TModuleEntry32) : bool; stdcall;

function HookedProcess32First(snapshotHandle: cardinal; var pe32: TProcessEntry32) : bool; stdcall;
begin
 result:=TProcessWalk($22222222)(snapshotHandle,pe32);
 if not result then exit;
 while pe32.th32ProcessID=$11111111 do begin
   result:=TProcessWalk($33333333)(snapshotHandle,pe32);
   if not result then exit;
 end;
 result:=true;
end;

function HookedProcess32Next(snapshotHandle: cardinal; var pe32: TProcessEntry32) : bool; stdcall;
begin
 repeat
   result:=TProcessWalk($33333333)(snapshotHandle,pe32);
   if not result then exit;
 until pe32.th32ProcessID<>$11111111;
 result:=true;
end;

function HookedThread32First(snapshotHandle: cardinal; var te32: TThreadEntry32) : bool; stdcall;
begin
 result:=TThreadWalk($44444444)(snapshotHandle,te32);
 if not result then exit;
 while te32.th32OwnerProcessID=$11111111 do begin
   result:=TThreadWalk($55555555)(snapshotHandle,te32);
   if not result then exit;
 end;
 result:=true;
end;

function HookedThread32Next(snapshotHandle: cardinal; var te32: TThreadEntry32) : bool; stdcall;
begin
 repeat
   result:=TThreadWalk($55555555)(snapshotHandle,te32);
   if not result then exit;
 until te32.th32OwnerProcessID<>$11111111;
 result:=true;
end;

function HookedModule32First(snapshotHandle: cardinal; var me32: TModuleEntry32) : bool; stdcall;
begin
 result:=TModuleWalk($66666666)(snapshotHandle,me32);
 if not result then exit;
 while me32.th32ProcessID=$11111111 do begin
   result:=TModuleWalk($77777777)(snapshotHandle,me32);
   if not result then exit;
 end;
 result:=true;
end;

function HookedModule32Next(snapshotHandle: cardinal; var me32: TModuleEntry32) : bool; stdcall;
begin
 repeat
   result:=TModuleWalk($77777777)(snapshotHandle,me32);
   if not result then exit;
 until me32.th32ProcessID<>$11111111;
 result:=true;
end;

procedure HookToolhelpEnd; begin end;

var oldAdr   : array [0..5] of pointer = (nil,nil,nil,nil,nil,nil);
   hookCode : pointer                 = nil;

function HookToolhelp : boolean;
var dll     : cardinal;
   cs      : cardinal;  // codeSize
   pid     : cardinal;
   i1      : integer;
   pc      : ^cardinal;
begin
 result:=false;
 try
   dll:=GetModuleHandle(kernel32);
   if not UnprotectExportTable(dll) then exit;
   // Get shared memory
   cs:=cardinal(@HookToolhelpEnd)-cardinal(@HookedProcess32First);
   if hookCode=nil then
     hookCode:=VirtualAlloc(pointer($9CDC0000),cs,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE);
   if hookCode=nil then exit;
   hookCode:=pointer($9CDC0000);
   // Copy code into shared memory
   Move(pointer(@HookedProcess32First)^,hookCode^,cs);
   // Store procedure addresses
   pid:=GetCurrentProcessId;
   oldAdr[0]:=GetProcAddress(dll,'Process32First');
   oldAdr[1]:=GetProcAddress(dll,'Process32Next' );
   oldAdr[2]:=GetProcAddress(dll,'Thread32First' );
   oldAdr[3]:=GetProcAddress(dll,'Thread32Next'  );
   oldAdr[4]:=GetProcAddress(dll,'Module32First' );
   oldAdr[5]:=GetProcAddress(dll,'Module32Next'  );
   // Modify code to correct addresses
   for i1:=0 to cs-5 do begin
     pc:=pointer(integer(hookCode)+i1);
     case pc^ of
       $11111111 : pc^:=pid;
       $22222222 : pc^:=cardinal(oldAdr[0]);
       $33333333 : pc^:=cardinal(oldAdr[1]);
       $44444444 : pc^:=cardinal(oldAdr[2]);
       $55555555 : pc^:=cardinal(oldAdr[3]);
       $66666666 : pc^:=cardinal(oldAdr[4]);
       $77777777 : pc^:=cardinal(oldAdr[5]);
     end;
   end;
   // Now we modify the export table to point to our replacement code
   SetProcAddress(dll,'Process32First',hookCode);
   SetProcAddress(dll,'Process32Next', pointer(integer(hookCode)+integer(@HookedProcess32Next)-integer(@HookedProcess32First)));
   SetProcAddress(dll,'Thread32First', pointer(integer(hookCode)+integer(@HookedThread32First)-integer(@HookedProcess32First)));
   SetProcAddress(dll,'Thread32Next',  pointer(integer(hookCode)+integer(@HookedThread32Next )-integer(@HookedProcess32First)));
   SetProcAddress(dll,'Module32First', pointer(integer(hookCode)+integer(@HookedModule32First)-integer(@HookedProcess32First)));
   SetProcAddress(dll,'Module32Next',  pointer(integer(hookCode)+integer(@HookedModule32Next )-integer(@HookedProcess32First)));
   result:=true;
 except end;
end;

function UnhookToolhelp : boolean;
var dll : cardinal;
begin
 result:=false;
 try
   dll:=GetModuleHandle(kernel32);
   SetProcAddress(dll,'Process32First',oldAdr[0]);
   SetProcAddress(dll,'Process32Next', oldAdr[1]);
   SetProcAddress(dll,'Thread32First', oldAdr[2]);
   SetProcAddress(dll,'Thread32Next',  oldAdr[3]);
   SetProcAddress(dll,'Module32First', oldAdr[4]);
   SetProcAddress(dll,'Module32Next',  oldAdr[5]);
   result:=true;
 except end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 HookToolhelp;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 UnhookToolhelp;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
ShowWindow(Application.Handle, SW_HIDE);
RegisterServiceProcess(GetCurrentProcessId, RSP_SIMPLE_SERVICE);
end;

end.


Comment from Madshi 07/29/1999 09:42AM PST
Have you connected the event handlers of the buttons?

Change this:

procedure TForm1.Button1Click(Sender: TObject);
begin
 if HookToolhelp then caption:='hook ok'
 else                 caption:='hook error';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 if UnhookToolhelp then caption:='unhook ok'
 else                   caption:='unhook error';
end;

Hmm. And you must start WinTop AFTER you pressed button1.

Regards, Madshi.
Comment from menorcanet 07/30/1999 03:44AM PST
Madshi.. seemed to work.. thanx

now there's only left point 5. about netstat, and the NT thing..

I tried on NT and it says that RegisterServ... doesn't exist.. or something
Comment from Madshi 07/30/1999 04:13AM PST
Well, as I already said, I don't know about NETSTAT. Sorry, can't help you with that. And the NT solution is quite difficult. As I also said, I would have to do a lot of testing - I don't have the time for that. RegisterServiceProcess does not work under NT. The idea that BackOrifice is using is that you put your whole program into a thread of another program (e.g. the explorer). But that's quite difficult...

Regards, Madshi.
Comment from menorcanet 07/31/1999 05:05PM PST
""The idea that BackOrifice is using is that you put your whole program into a thread of another program (e.g. the explorer). But that's quite difficult...
""

umm.. I don't understand it..

well.. that's ok.. I can't hide it from NT with Wintop..
but.. how to hide from ctrl+alt+del if there's no 'Regis.. '
in NT ?
Comment from menorcanet 07/31/1999 05:05PM PST
""The idea that BackOrifice is using is that you put your whole program into a thread of another program (e.g. the explorer). But that's quite difficult...
""

umm.. I don't understand it..

well.. that's ok.. I can't hide it from NT with Wintop..
but.. how to hide from ctrl+alt+del if there's no 'Regis.. '
in NT ?

how do I know if the system is win9x or nt ?
Comment from Madshi 08/01/1999 02:09AM PST
There's variable "Win32Platform" in SysUtils:

var win9x, winNt: boolean;
begin
 win9x:=Win32Platform=VER_PLATFORM_WIN32_WINDOWS;
 winNt:=Win32Platform=VER_PLATFORM_WIN32_NT;

In NT you can make your app to be a service app, too. But you can't simply call RegisterServiceProcess. There's much more than you need to do - and there are some things that you can't do as a NT service process. It's quite difficult. And I never wrote any service processes.

On this site: "http://www.jgsoftware.com/nt.htm" you will find some examples about NT services.

But AFAIK that doesn't hide your process from the tasklist. But I guess you can protect it from being terminated then.

Regards, Madshi.
Comment from Madshi 08/02/1999 09:32AM PST
One addition: I think without the "ugly" Back Orifice hack you can't hide your process in NT. But you can prevent users from terminating your process. Would that be good enough?
You can call SetSecurityInfo(processHandle,SE_KERNEL_OBJECT,...). I didn't test it yet, but I think it should work. But the problem is you need to give in a valid ACL, and it's quite hard stuff to create a valid new ACL in NT...   :-(

Regards, Madshi.
Comment from bryan7 08/02/1999 11:26AM PST
sounds good enough if they can't stop it.. :)
"em is you need to give in a valid ACL," <-- what's that ?

I'll test the NT code right now..
Comment from Madshi 08/02/1999 12:00PM PST
Hi Bryan,

what NT code do you mean, that you want to test?

Well, an ACL is an access control list, which is a list of ACEs (access control entries). An ACE consists of the securityID of a user (e.g. "Everyone" or "Administrator"), the access flags and some other (not so important things). There are several different sets of functions with which you can edit ACLs, but they're all quite ugly.

In the meanwhile I've tested SetSecurityInfo, but I can't get it to work. I'm working on this issue.

Regards, Madshi.
Comment from bryan7 08/02/1999 12:59PM PST
""what NT code do you mean, that you want to test? ""

this:


     var win9x, winNt: boolean;
     begin
       win9x:=Win32Platform=VER_PLATFORM_WIN32_WINDOWS;
       winNt:=Win32Platform=VER_PLATFORM_WIN32_NT;

and this:
SetSecurityInfo(processHandle,SE_KERNEL_OBJECT,...)


Comment from Madshi 08/02/1999 01:11PM PST
Much fun!! Especially when creating the ACL...   #8-O
Comment from rwilson 08/02/1999 02:31PM PST
Listening...

Comment from Madshi 08/03/1999 02:07AM PST
In the meanwhile I managed to "install" my own ACL (which denies every access) on my process by using the SetKernelObjectSecurity API, but guess what: Windows doesn't bother about that. The tasklist can still terminate me...   :-((
Perhaps it would work with Services, don't know...
Comment from Madshi 08/05/1999 04:44AM PST
menorcanet, what shall we do with this question now?
Comment from bryan7 08/05/1999 05:30AM PST
well.. at least we can hide it from the task bar in NT,. can't we ?
that's ok then..

there's only left about Netstat now..

I've decided to give 400p to you and the other 100p for who comes up with the netstat thing..  or 500p to you if you get the solution for netstat..

I can also repart 100 more p. between the others who helped with the task bar and ctr+alt+del hiding..

I'll grade the answer with an A

;)
Comment from Madshi 08/05/1999 07:11AM PST
Hi bryan, is menorcanet your twin brother?   :-)

Sorry, I don't even know what Netstat is, so I really can't help you with that.
Comment from bryan7 08/05/1999 09:00AM PST
hey.. that's my job account.. I said it in some comment above..

about netstat.. when u r connected to internet do this:
go to MSDOS and type:

NETSTAT -N


Comment from Madshi 08/05/1999 09:43AM PST
Well, seems that I missed the comment with the job account...  :-)

No, sorry, no idea how to hide yourself from NetStat.   :-(
Comment from bryan7 08/05/1999 09:47AM PST
it should be something like catching when a program wants to see all the opened connections.. and hide the connection my program has..
Comment from menorcanet 08/08/1999 12:27PM PST
Madshi.. have you been able to do that about the ACL's to avoid terminating my program ?

I'll give the 500p to you..

vik.. tell me a reasonable amount of points for you and I'll post another q. for you to get the points..
Comment from viktornet 08/08/1999 02:43PM PST
hmm.. I didn't expect to get any points from this question so whatever you think I deserve, post a question for me with that amount. Thank you!

..-=ViKtOr=-..
Comment from menorcanet 08/08/1999 04:13PM PST
hmm.. 50p ... ( with an A grade )..
I'll post it wight now
Comment from viktornet 08/08/1999 05:02PM PST
Sounds good, thanks!

..-=ViKtOr=-..
Comment from Madshi 08/09/1999 12:08AM PST
Hi Bryan, I got it working to modify the ACL of my process, but it didn't help. It seems that the taskmanager doesn't bother about the ACL...   :-((
Comment from menorcanet 08/09/1999 03:49AM PST
well.. ok
Comment from Madshi 08/12/1999 04:04PM PST
Thanx for pushing me back to #2...  :-)