aguml |
31-05-2020 23:24:37 |
Veis fallos de liberación de memoria?
Buenas amigos, he creado este código y me gustaria que me dijeran si estoy liberando bien los hilos o me dejo algo por ahí que no debería:
El .h:
Código PHP:
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <System.hpp>
#include <Vcl.ComCtrls.hpp>
#include <Syncobjs.hpp>
//---------------------------------------------------------------------------
typedef struct {
UCHAR BeingDebugger;
UCHAR NTGlobalFlag;
UCHAR ProcessHeapFlags;
UCHAR ProcessHeapForceFlags;
}PEB_DETECTION;
PEB_DETECTION *ProtectPeb;
typedef struct {
WideString cadena;
bool isDebugger;
}Salida;
typedef struct {
Salida IsDebuggerPresent;
Salida BeingDebugger;
Salida NTGlobalFlag;
Salida ProcessHeapFlags;
Salida ProcessHeapForceFlags;
Salida DebugPort;
Salida NtSetInformationThread;
Salida CloseHandleWithInvalidHandle;
Salida GetTickCount;
Salida timeGetTime;
Salida QueryPerformanceCounter;
Salida OutputDebugString;
}RETURN_DETECTION;
RETURN_DETECTION *Deteccion;
typedef struct { //Para truco con QueryPerformanceCounter
__int64 TimeInit;
__int64 TimeEnd;
}sTimer64;
class TMyThread : public TThread
{
private:
sTimer64 gtc, tgt;
sTimer64 qpc;
PEB_DETECTION PEB_Protection;
RETURN_DETECTION Return_Detection;
protected:
void __fastcall Execute();
public:
__fastcall TMyThread(bool CreateSuspended,sTimer64,sTimer64,sTimer64);
void __fastcall ObtainStringsTimes(sTimer64, sTimer64, sTimer64);
void __fastcall ShowMessagesTimes(void);
void __fastcall SendTextColored(Salida s);
};
class TMyThread2 : public TThread
{
private:
sTimer64 gtc, tgt;
sTimer64 qpc;
TMyThread *hilo; //Hilo para poder probar las protecciones de tiempo con una pausa Sleep sin congelar el form
void __fastcall CheckDebug(void);
void __fastcall ObtenerDatosPEBx64(PEB_DETECTION *Peb_Protection);
void __fastcall ObtenerDatosPEBx32(PEB_DETECTION *Peb_Protection);
void __fastcall QueryDetectionPEB(PEB_DETECTION *Peb_Protection, RETURN_DETECTION *Detection);
bool __fastcall QueryDebugPortDetection(void);
bool __fastcall QueryNtSetInformationThread(void);
bool __stdcall ObjectListCheck(RETURN_DETECTION *Detection);
bool __fastcall CheckOutputDebugString(void);
protected:
void __fastcall Execute();
public:
__fastcall TMyThread2(bool CreateSuspended);
static TEvent *EventDatosLlenos;
};
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *ButtonPEB;
TCheckBox *CheckBox1;
TRichEdit *RichEditLogAntiDebug;
private: // User declarations
public: // User declarations
TMyThread2 *hilo2;
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
El .cpp:
Código PHP:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <Windows.h>
#include <Mmsystem.h>
#include <winnt.h>
#pragma hdrstop
#include "Unit1.h"
#define ObjectAllInformation 3
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TEvent* TMyThread2::EventDatosLlenos = new TEvent(false);
//#undef _WIN64 //Para poder compilar en x32
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
hilo2 = new TMyThread2(false);
}
//---------------------------------------------------------------------------
#ifdef _WIN64
void __fastcall TForm1::ObtenerDatosPEBx64(PEB_DETECTION *Peb_Protection)
{
DWORD64 PEB;
DWORD64 read;
DWORD64 dwBeingDebugger, dwNTGlobalFlag, dwProcessHeapFlags, dwProcessHeapForceFlags;
//Obtengo el PEB
__asm
{
mov rax, gs:[0x60];
mov PEB, rax;
}
//Obtenemos el valor de BeingDebugger
dwBeingDebugger = PEB+0x2;
ReadProcessMemory(GetCurrentProcess(),(LPVOID)dwBeingDebugger,&Peb_Protection->BeingDebugger ,sizeof(Peb_Protection->BeingDebugger),(DWORD64*)&read);
//Obtenemos el valor de NtGlobalFlag
dwNTGlobalFlag = PEB+0xBC;
ReadProcessMemory(GetCurrentProcess(),(LPVOID)dwNTGlobalFlag,&Peb_Protection->NTGlobalFlag,sizeof(Peb_Protection->NTGlobalFlag),(DWORD64*)&read);
//Obtenemos el valor de ProcessHeapFlags
ReadProcessMemory(GetCurrentProcess(),(LPVOID)(PEB+0x30),&dwProcessHeapFlags ,sizeof(dwProcessHeapFlags),(DWORD64*)&read);
dwProcessHeapFlags += 0x70;
ReadProcessMemory(GetCurrentProcess(),(LPVOID)(dwProcessHeapFlags),&Peb_Protection->ProcessHeapFlags ,sizeof(Peb_Protection->ProcessHeapFlags),(DWORD64*)&read);
//Obtenemos el valor de ProcessHeapForceFlags
ReadProcessMemory(GetCurrentProcess(),(LPVOID)(PEB+0x30),&dwProcessHeapForceFlags ,sizeof(dwProcessHeapForceFlags),(DWORD64*)&read);
dwProcessHeapForceFlags += 0x74;
ReadProcessMemory(GetCurrentProcess(),(LPVOID)(dwProcessHeapForceFlags),&Peb_Protection->ProcessHeapForceFlags ,sizeof(Peb_Protection->ProcessHeapForceFlags),(DWORD64*)&read);
}
#elif defined _WIN32
void __fastcall TMyThread2::ObtenerDatosPEBx32(PEB_DETECTION *Peb_Protection)
{
DWORD PEB;
DWORD read;
DWORD dwBeingDebugger, dwNTGlobalFlag, dwProcessHeapFlags, dwProcessHeapForceFlags;
//Obtengo el PEB
__asm
{
mov eax, fs:[0x30];
mov PEB, eax;
}
//Obtenemos el valor de BeingDebugger
dwBeingDebugger = PEB+0x2;
ReadProcessMemory(GetCurrentProcess(),(LPVOID)dwBeingDebugger,&Peb_Protection->BeingDebugger ,sizeof(Peb_Protection->BeingDebugger),(DWORD*)&read);
//Obtenemos el valor de NtGlobalFlag
dwNTGlobalFlag = PEB+0x68;
ReadProcessMemory(GetCurrentProcess(),(LPVOID)dwNTGlobalFlag,&Peb_Protection->NTGlobalFlag,sizeof(Peb_Protection->NTGlobalFlag),(DWORD*)&read);
//Obtenemos el valor de ProcessHeapFlags
ReadProcessMemory(GetCurrentProcess(),(LPVOID)(PEB+0x18),&dwProcessHeapFlags ,sizeof(dwProcessHeapFlags),(DWORD*)&read);
dwProcessHeapFlags += 0x40;
ReadProcessMemory(GetCurrentProcess(),(LPVOID)(dwProcessHeapFlags),&Peb_Protection->ProcessHeapFlags ,sizeof(Peb_Protection->ProcessHeapFlags),(DWORD*)&read);
//Obtenemos el valor de ProcessHeapForceFlags
ReadProcessMemory(GetCurrentProcess(),(LPVOID)(PEB+0x18),&dwProcessHeapForceFlags ,sizeof(dwProcessHeapForceFlags),(DWORD*)&read);
dwProcessHeapForceFlags += 0x44;
ReadProcessMemory(GetCurrentProcess(),(LPVOID)(dwProcessHeapForceFlags),&Peb_Protection->ProcessHeapForceFlags ,sizeof(Peb_Protection->ProcessHeapForceFlags),(DWORD*)&read);
}
#endif
//---------------------------------------------------------------------------
bool __fastcall TMyThread2::QueryDebugPortDetection(void)
{
ULONG ProcessDebugPort = 7;
DWORD read;
HMODULE NtDll;
ULONG status;
bool retval;
NtDll = LoadLibrary(L"ntdll.dll");
LONG (WINAPI *NtQueryInformationProcess)(HANDLE ProcessHandle, ULONG ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
*(FARPROC *)&NtQueryInformationProcess = GetProcAddress(NtDll, "NtQueryInformationProcess");
HANDLE DebugPort;
status = NtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort, &DebugPort, sizeof(DebugPort), &read);
if(DebugPort)
{
retval=true;
}
else
{
retval=false;
}
return retval;
}
//---------------------------------------------------------------------------
bool __fastcall TMyThread2::QueryNtSetInformationThread(void)
{
HMODULE NtDll;
NTSTATUS ntStat;
bool check = false;
bool retval=false;
int ThreadHideFromDebugger = 0x11;
NtDll = LoadLibrary(L"ntdll.dll");
LONG (WINAPI *NtSetInformationThread)(HANDLE ThreadHandle, ULONG ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength);
LONG (WINAPI *NtQueryInformationThread)(HANDLE ThreadHandle, ULONG ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength);
*(FARPROC *)&NtSetInformationThread = GetProcAddress(NtDll, "NtSetInformationThread");
*(FARPROC *)&NtQueryInformationThread = GetProcAddress(NtDll, "NtQueryInformationThread");
//invalid parameter
ntStat = NtSetInformationThread(NULL, ThreadHideFromDebugger, &check, sizeof(ULONG));
if (ntStat >= 0) //it must fail
{
//Detectado con metodo 1
return true;
}
//invalid handle
ntStat = NtSetInformationThread((HANDLE)0xFFFFF, ThreadHideFromDebugger, 0, 0);
if (ntStat >= 0) //it must fail
{
//Detectado con metodo 2
return true;
}
//En x32 si estamos depurandolo se cerrará directamente el proceso
ntStat = NtSetInformationThread(NULL, ThreadHideFromDebugger, 0, 0);
if (ntStat >= 0)
{
//only available >= VISTA
ntStat = NtQueryInformationThread(NULL, ThreadHideFromDebugger, &check, sizeof(bool), 0);
if (ntStat >= 0)
{
if (!check)
{
//Detectado con metodo 4
return true;
}
else
{
return false;
}
}
else
{
ShowMessage("Query ThreadHideFromDebugger no disponible!");
retval=false;
}
}
else
{
//Detectado con metodo 3
return true;
}
return retval;
}
//---------------------------------------------------------------------------
void __fastcall TMyThread2::QueryDetectionPEB(PEB_DETECTION *Peb_Protection, RETURN_DETECTION *Detection)
{
#ifdef _WIN64
ObtenerDatosPEBx64(Peb_Protection);
#elif defined _WIN32
ObtenerDatosPEBx32(Peb_Protection);
#else
#error "Error. Solo sirve para Windows"
#endif
if(Peb_Protection->BeingDebugger == 0x1)
{
Detection->BeingDebugger.cadena = "BeingDebugger te ha detectado.";
Detection->BeingDebugger.isDebugger = true;
}else{
Detection->BeingDebugger.cadena = "BeingDebugger no te ha detectado.";
Detection->BeingDebugger.isDebugger = false;
}
if(Peb_Protection->NTGlobalFlag == 0x70)
{
Detection->NTGlobalFlag.cadena = "NtGlobalFlag te ha detectado.";
Detection->NTGlobalFlag.isDebugger = true;
}else{
Detection->NTGlobalFlag.cadena = "NtGlobalFlag no te ha detectado.";
Detection->NTGlobalFlag.isDebugger = false;
}
if(Peb_Protection->ProcessHeapFlags != 2)
{
Detection->ProcessHeapFlags.cadena = "ProcessHeapFlags te ha detectado.";
Detection->ProcessHeapFlags.isDebugger = true;
}else{
Detection->ProcessHeapFlags.cadena = "ProcessHeapFlags no te ha detectado.";
Detection->ProcessHeapFlags.isDebugger = false;
}
if(Peb_Protection->ProcessHeapForceFlags != 0)
{
Detection->ProcessHeapForceFlags.cadena = "ProcessHeapForceFlags te ha detectado.";
Detection->ProcessHeapForceFlags.isDebugger = true;
}else{
Detection->ProcessHeapForceFlags.cadena = "ProcessHeapForceFlags no te ha detectado.";
Detection->ProcessHeapForceFlags.isDebugger = false;
}
}
//---------------------------------------------------------------------------
bool __fastcall TMyThread2::CheckOutputDebugString(void)
{
wchar_t lpOutputString[]=L"Hello Debugger!";
char outputDebugStringBuffer[1000] = {0};
bool retval;
WideCharToMultiByte(CP_ACP, 0, lpOutputString, -1, outputDebugStringBuffer, sizeof(outputDebugStringBuffer), 0, 0);
ULONG_PTR args[4];
//unicode
args[0] = (ULONG_PTR)wcslen(lpOutputString) + 1;
args[1] = (ULONG_PTR)lpOutputString;
//ansi for compatibility
args[2] = (ULONG_PTR)wcslen(lpOutputString) + 1;
args[3] = (ULONG_PTR)outputDebugStringBuffer;
__try
{
RaiseException(0x4001000A, 0, 4, args);//DBG_PRINTEXCEPTION_WIDE_C
retval = true;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
retval = false;
}
return retval;
}
//---------------------------------------------------------------------------
void __fastcall TMyThread2::CheckDebug(void)
{
ProtectPeb= new(PEB_DETECTION);
Deteccion = new(RETURN_DETECTION);
HANDLE hTrucho = (HANDLE)1234; //Para truco con CloseHandle
QueryPerformanceCounter((LARGE_INTEGER*)&qpc.TimeInit); //Obtenemos el tiempo inicial con QueryPerformanceCounter
tgt.TimeInit = timeGetTime();
gtc.TimeInit = GetTickCount(); //Obtenemos el tiempo inicial con GetTickCount
if(hilo == NULL)
hilo = new TMyThread(false,gtc,tgt,qpc); //Creo un hilo para controlar el tiempo y poder pausar para probar el antiantidebug
if(ProtectPeb != NULL && Deteccion != NULL && hilo != NULL)
{
Deteccion->IsDebuggerPresent.isDebugger = IsDebuggerPresent();
if(Deteccion->IsDebuggerPresent.isDebugger){
Deteccion->IsDebuggerPresent.cadena = "Detectado por IsDebuggerPresent.";
}else{
Deteccion->IsDebuggerPresent.cadena = "No detectado por IsDebuggerPresent.";
}
Deteccion->CloseHandleWithInvalidHandle.cadena = "No detectado por CloseHandle con un handle inválido.";
Deteccion->CloseHandleWithInvalidHandle.isDebugger = false;
__try{
CloseHandle(hTrucho);
}
__except(EXCEPTION_EXECUTE_HANDLER){
Deteccion->CloseHandleWithInvalidHandle.cadena = "Detectado por CloseHandle con un handle inválido.";
Deteccion->CloseHandleWithInvalidHandle.isDebugger = true;
}
QueryDetectionPEB(ProtectPeb, Deteccion);
Deteccion->DebugPort.isDebugger = QueryDebugPortDetection();
if(Deteccion->DebugPort.isDebugger){
Deteccion->DebugPort.cadena = "DebugPort te ha detectado.";
Deteccion->DebugPort.isDebugger = true;
}
else
{
Deteccion->DebugPort.cadena = "DebugPort no te ha detectado.";
Deteccion->DebugPort.isDebugger = false;
}
Deteccion->OutputDebugString.isDebugger = CheckOutputDebugString();
if(Deteccion->OutputDebugString.isDebugger){
Deteccion->OutputDebugString.cadena = "Debugger detectado con OutputDebugString.";
Deteccion->OutputDebugString.isDebugger = true;
}
else
{
Deteccion->OutputDebugString.cadena = "Debugger no detectado con OutputDebugString.";
Deteccion->OutputDebugString.isDebugger = false;
}
Deteccion->BeingDebugger.cadena = Deteccion->BeingDebugger.cadena + " Resultado = 0x"+WideString(IntToHex((int)ProtectPeb->BeingDebugger,2));
Deteccion->NTGlobalFlag.cadena = Deteccion->NTGlobalFlag.cadena + " Resultado = 0x"+WideString(IntToHex((int)ProtectPeb->NTGlobalFlag,2));
Deteccion->ProcessHeapFlags.cadena = Deteccion->ProcessHeapFlags.cadena + " Resultado = 0x"+WideString(IntToHex((int)ProtectPeb->ProcessHeapFlags,2));
Deteccion->ProcessHeapForceFlags.cadena = Deteccion->ProcessHeapForceFlags.cadena + " Resultado = 0x"+WideString(IntToHex((int)ProtectPeb->ProcessHeapForceFlags,2));
//Deteccion->NtSetInformationThread.isDebugger = QueryNtSetInformationThread();
if(Deteccion->NtSetInformationThread.isDebugger)
{
Deteccion->NtSetInformationThread.cadena = "NtSetInformationThread nos ha desatacheado.";
}else{
Deteccion->NtSetInformationThread.cadena = "NtSetInformationThread pasado con éxito.";
}
EventDatosLlenos->SetEvent();
}else{
ShowMessage("Hubo un problema al asignar memoria");
}
}
//---------------------------------------------------------------------------
__fastcall TMyThread::TMyThread(bool CreateSuspended, sTimer64 sGetTickCount, sTimer64 sTimeGetTime, sTimer64 sQueryPerformanceCounter): TThread(CreateSuspended)
{
//FreeOnTerminate=true;
memcpy(>c,&sGetTickCount,sizeof(sTimer64));
memcpy(&tgt,&sTimeGetTime,sizeof(sTimer64));
memcpy(&qpc,&sQueryPerformanceCounter,sizeof(sTimer64));
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{
if(Form1->CheckBox1->Checked)
Sleep(3000); //Necesario para comprobar si nos detectan por tiempo aunque asi nos detecte siempre
else
Sleep(100);
ObtainStringsTimes(tgt,gtc,qpc);
Synchronize(ShowMessagesTimes);
delete ProtectPeb;
delete Deteccion;
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::SendTextColored(Salida s)
{
if(s.isDebugger==true)
Form1->RichEditLogAntiDebug->SelAttributes->Color = clRed;
else
Form1->RichEditLogAntiDebug->SelAttributes->Color = clLime;
Form1->RichEditLogAntiDebug->Lines->Add(s.cadena);
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::ShowMessagesTimes()
{
TMyThread2::EventDatosLlenos->WaitFor(INFINITE);
//Mostramos los datos
Form1->RichEditLogAntiDebug->Clear();
SendTextColored(Deteccion->IsDebuggerPresent);
SendTextColored(Deteccion->BeingDebugger);
SendTextColored(Deteccion->NTGlobalFlag);
SendTextColored(Deteccion->ProcessHeapFlags);
SendTextColored(Deteccion->ProcessHeapForceFlags);
SendTextColored(Deteccion->DebugPort);
SendTextColored(Deteccion->CloseHandleWithInvalidHandle);
SendTextColored(Deteccion->OutputDebugString);
SendTextColored(Deteccion->NtSetInformationThread);
//Mostramos si nos ha detectado con GetTickCount o no y posicionamos al inicio el TMEMO
SendTextColored(Deteccion->GetTickCount);
SendTextColored(Deteccion->timeGetTime);
SendTextColored(Deteccion->QueryPerformanceCounter);
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::ObtainStringsTimes(sTimer64 tgc, sTimer64 gtc,sTimer64 qpc)
{
__int64 frec=0;
gtc.TimeEnd = GetTickCount(); //Obtenemos el tiempo final con GetTickCount
tgc.TimeEnd = timeGetTime(); //Obtenemos el tiempo final con timeGetTime
QueryPerformanceCounter((LARGE_INTEGER*)&(qpc.TimeEnd)); //Obtenemos el tiempo final con QueryPerformanceCounter
//Obtenemos la frecuencia
QueryPerformanceFrequency((LARGE_INTEGER*)&frec);
//Aqui comprobamos que el tiempo transcurrido no pase de 2 segundos en milisegundos
if((gtc.TimeEnd - gtc.TimeInit) > 2000)
{
Deteccion->GetTickCount.cadena = "Detectado con método GetTickCount.";
Deteccion->GetTickCount.isDebugger = true;
}else{
Deteccion->GetTickCount.cadena = "No detectado con método GetTickCount.";
Deteccion->GetTickCount.isDebugger = false;
}
//Aqui comprobamos que el tiempo transcurrido usando timeGetTime no pase de 2 segundos en milisegundos
if((tgc.TimeEnd - tgc.TimeInit) > 2000)
{
Deteccion->timeGetTime.cadena = "Detectado con método timeGetTime.";
Deteccion->timeGetTime.isDebugger = true;
}else{
Deteccion->timeGetTime.cadena = "No detectado con método timeGetTime.";
Deteccion->timeGetTime.isDebugger = false;
}
//Aqui comprobamos que el tiempo transcurrido usando QueryPerformanceCounter no pase de 2 segundos en milisegundos
if((qpc.TimeEnd - qpc.TimeInit)/(frec/1000) > 2000)
{
Deteccion->QueryPerformanceCounter.cadena = "Detectado con método QueryPerformanceCounter.";
Deteccion->QueryPerformanceCounter.isDebugger = true;
}else{
Deteccion->QueryPerformanceCounter.cadena = "No detectado con método QueryPerformanceCounter.";
Deteccion->QueryPerformanceCounter.isDebugger = false;
}
}
//---------------------------------------------------------------------------
__fastcall TMyThread2::TMyThread2(bool CreateSuspended)
{
FreeOnTerminate = true;
hilo=NULL;
}
//---------------------------------------------------------------------------
void __fastcall TMyThread2::Execute()
{
do{
if(hilo != NULL){
hilo->WaitFor();
delete hilo;
hilo = NULL;
}
CheckDebug();
}while(true);
}
//---------------------------------------------------------------------------
La aplicacion aparentemente realiza bien la tarea aunque no me ha gustado tener que poner un Sleep(100) para que no parpadee la pantalla cuando no marco el checkbox ya que limpio el RichEdit y lo vuelvo a pintar. Se que eso se arreglaba desactivando el repintado o algo asi y luego pintando (no recuerdo como era...
¿Como lo mejoraríais?
|