PDA

Ver la Versión Completa : Problemas de conversion de código de x32 a x64


aguml
20-05-2020, 00:04:15
Buenas amigos, a parte de que algunas funciones de Windows ahora necesiten wchar_t* en vez de char* y int64_t en lugar de int, me encuentro con algunos problemas más que no sé cómo salvar. El primero es la estructura CONTEXT la cual contiene información de un proceso como los flags y registros, en x64 no me la reconoce ¿Sabéis cual es su equivalente para x64?
Otro es el DWORD que he visto que tiene que ser DWORD64 pero no sé si eso existe en c++builder o tiene que ser uint64_t o algo así.

ecfisa
20-05-2020, 05:43:33
Hola.

Revisa si el siguiente enlace te ayuda en algo: 64-bit Windows Data Types Compared to 32-bit Windows Data Types (http://docwiki.embarcadero.com/RADStudio/Rio/en/64-bit_Windows_Data_Types_Compared_to_32-bit_Windows_Data_Types)

Saludos :)

aguml
20-05-2020, 10:43:06
Gracias, me está sirviendo de ayuda aunque esto va para largo ya que una vez me compile tendré que revisar todo y ver como funciona cada cosa y estudiar como funcionan en x64 porque hay muchas que seguramente no coincidan con el funcionamiento de x32.
Tengo ahora mismo tres problemas/dudas:
1-No se que pasa con el tipo CONTEXT que si hago por ejemplo
CONTEXT con;
con.
el único método que sale es operator= y no aparecen ni los registros, ni flags ni nada de esa estructura. Estuve viendo que por internet decian que era por no tener el SDK y no lo tenia porque al instalarlo desde el instalador de RAD 10.3 Rio me daba error diciendo que no se podía conectar a internet o algo así por lo que me lo descargué directamente de Microsoft y lo añadí desde Tools->Options...->Deployment->SDK Manager y no tuve problemas al hacerlo pero sigo teniendo el mismo problema de que no puedo trabajar con el contenido de la estructura CONTEXT. He hecho clic derecho sobre CONTEXT y buscado su declaración y me sale en winnt.h toda la estructura pero sin embargo no puedo usarla T.T
typedef struct DECLSPEC_ALIGN(16) _CONTEXT {

//
// Register parameter home addresses.
//
// N.B. These fields are for convience - they could be used to extend the
// context record in the future.
//

DWORD64 P1Home;
DWORD64 P2Home;
DWORD64 P3Home;
DWORD64 P4Home;
DWORD64 P5Home;
DWORD64 P6Home;

//
// Control flags.
//

DWORD ContextFlags;
DWORD MxCsr;

//
// Segment Registers and processor flags.
//

WORD SegCs;
WORD SegDs;
WORD SegEs;
WORD SegFs;
WORD SegGs;
WORD SegSs;
DWORD EFlags;

//
// Debug registers
//

DWORD64 Dr0;
DWORD64 Dr1;
DWORD64 Dr2;
DWORD64 Dr3;
DWORD64 Dr6;
DWORD64 Dr7;

//
// Integer registers.
//

DWORD64 Rax;
DWORD64 Rcx;
DWORD64 Rdx;
DWORD64 Rbx;
DWORD64 Rsp;
DWORD64 Rbp;
DWORD64 Rsi;
DWORD64 Rdi;
DWORD64 R8;
DWORD64 R9;
DWORD64 R10;
DWORD64 R11;
DWORD64 R12;
DWORD64 R13;
DWORD64 R14;
DWORD64 R15;

//
// Program counter.
//

DWORD64 Rip;

//
// Floating point state.
//

union {
XMM_SAVE_AREA32 FltSave;
struct {
M128A Header[2];
M128A Legacy[8];
M128A Xmm0;
M128A Xmm1;
M128A Xmm2;
M128A Xmm3;
M128A Xmm4;
M128A Xmm5;
M128A Xmm6;
M128A Xmm7;
M128A Xmm8;
M128A Xmm9;
M128A Xmm10;
M128A Xmm11;
M128A Xmm12;
M128A Xmm13;
M128A Xmm14;
M128A Xmm15;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;

//
// Vector registers.
//

M128A VectorRegister[26];
DWORD64 VectorControl;

//
// Special debug control registers.
//

DWORD64 DebugControl;
DWORD64 LastBranchToRip;
DWORD64 LastBranchFromRip;
DWORD64 LastExceptionToRip;
DWORD64 LastExceptionFromRip;
} CONTEXT, *PCONTEXT;

2-Tengo varios TList los cuales uso para guardar cosas como datos de DLLs, BPs, HBPs... los cuales cuando ya no lo necesito tengo que liberar toda esa memoria y en x32 lo tenia así:
delete ListaBPs->Items[pos];
ListaBPs->Delete(pos);
En la primera linea, donde intento liberar la memoria del item, me da el siguiente Warning:
[bcc64 Warning] THiloDebugger.cpp(1839): cannot delete expression with pointer-to-'void' type 'void *'
No se si tengo que preocuparme o no por esa advertencia.

3-No me acepta la estructura __try catch(...), en su lugar he tenido que usar __try __except(EXCEPTION_EXECUTE_HANDLER)
¿hay alguna diferencia entre uno y otro? y por otro lado ¿que diferencia hay entre __try catch(...) y try catch(...)?
Ahora mismo los tengo así:
void __fastcall TAntiAntiDebug::DeactiveInvalidHandle(bool estado)
{
__try{
if(HiloDepuracion != NULL)
HiloDepuracion->DeactiveInvalidHandle(estado);
}__except(EXCEPTION_EXECUTE_HANDLER){
}
}
Pero no se si con un try catch(...) bastaría.

aguml
20-05-2020, 16:02:36
Pues pasa algo raro, aunque al poner el punto no me ofrece ninguno de los miembros que forman parte de la estructura, si lo pongo yo si lo acepta así que guiándome de esa estructura estoy corrigiendo todo lo que pueda pero en algunos puntos me veo que no puedo porque no se para que son algunos de ellos y a que equivalían en x32 para modificar sus respectivos métodos de x32 y convertirlos a x64.
Por ejemplo:
void THiloDebugger::SetEAX(DWORD Valor)
{
con.Eax = Valor;
}

Quedó así:
void THiloDebugger::SetRAX(DWORD64 Valor)
{
con.Rax = Valor;
}

Las de los Flags,Drx (los de los Hardware Breakpoints), ContextFlags, los SegXs no hay problema porque coinciden con los de x32.
Del resto no tengo ni idea de para que son y como leerlos y escribirlos y que utilidad podría tener leerlos o escribirlos.

aguml
20-05-2020, 22:52:29
He conseguido encontrar info por la red y he reajustado todo para que me lea los registros de x64 (o eso creo porque eso está aun por ver) pero ahora tengo un problema y es que en el de x32 usaba EnumProcessModules para cuando me atacheo a un proceso poder saber las dlls que tenia cargadas el proceso y al cambiar a x64 vi que en la msdn dice que hay que usar EnumProcessModulesEx y el problema que tengo es que me da un error sobre la libreria psapi.lib:
[ilink64 Error] Fatal: Invalid object file 'C:\USERS\AGUSTIN\DESKTOP\PROYECTO TDEBUGGER CON C++BUILDER 10.3 RIO X64\CLASE TDEBUGGER\PSAPI.LIB'
En x32 no fallaba esa libreria :confused:
¿Alguna idea?

aguml
21-05-2020, 09:01:28
Arreglado eso también. lo tenía como:
#pragma comment(lib,"psapi.lib")
y lo dejé como:
#pragma comment(lib,"psapi")
por lo que he podido leer, en x64 se usan las librerías con extensión .a y no .lib y por eso me daba el problema. Poniéndolo como lo tengo ahora he leído que elige la que mejor se adapta, o sea que es mas portable.
Ahora mismo ya compila y me queda lo mas duro, comprobar todo y reparar fallos.

aguml
21-05-2020, 16:41:25
Ahora tengo otro problema, no me lee el CONTEXT. Lo tengo asi:
CONTEXT con;
...
...
...
con.ContextFlags= CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS;
if(GetThreadContext(CurrentExceptionThread, &con)==0){
ShowMessage(WideString().sprintf(L"Error: %i",GetLastError()));
salir=true;
}

Y me muestra el error 998 que según la lista es ERROR_NOACCESS. ¿Que hago mal para que no me funcione? :confused:
Para crear el proceso lo tengo así:
STARTUPINFO si;
PROCESS_INFORMATION pi;
...
...
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
CreateProcess(PathFile.c_bstr(),NULL, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi);

aguml
21-05-2020, 21:52:58
He visto un poco el código de Titán enginer y veo que inicializa de forma diferente CONTEXT:
DBGContext.ContextFlags = CONTEXT_ALL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS;
Y para crear el proceso lo hace así:

__declspec(dllexport) void* TITCALL InitDebugW(wchar_t* szFileName, wchar_t* szCommandLine, wchar_t* szCurrentFolder)
{
int DebugConsoleFlag = NULL;

if(DebugDebuggingDLL)
{
DebugConsoleFlag = CREATE_NO_WINDOW | CREATE_SUSPENDED;
}
else if(engineRemoveConsoleForDebugee)
{
DebugConsoleFlag = CREATE_NO_WINDOW;
}

if(engineEnableDebugPrivilege)
{
EngineSetDebugPrivilege(GetCurrentProcess(), true);
DebugRemoveDebugPrivilege = true;
}
wchar_t* szFileNameCreateProcess;
wchar_t* szCommandLineCreateProcess;
std::wstring createWithCmdLine;
if(szCommandLine == NULL || !lstrlenW(szCommandLine))
{
szCommandLineCreateProcess = 0;
szFileNameCreateProcess = szFileName;
}
else
{
createWithCmdLine.push_back('\"');
createWithCmdLine.append(szFileName);
createWithCmdLine.push_back('\"');
createWithCmdLine.push_back(' ');
createWithCmdLine.append(szCommandLine);
szCommandLineCreateProcess = (wchar_t*)createWithCmdLine.c_str();
szFileNameCreateProcess = 0;
}
if(CreateProcessW(szFileNameCreateProcess, szCommandLineCreateProcess, NULL, NULL, false, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | DebugConsoleFlag | CREATE_NEW_CONSOLE, NULL, szCurrentFolder, &dbgStartupInfo, &dbgProcessInformation))
{
if(engineEnableDebugPrivilege)
EngineSetDebugPrivilege(GetCurrentProcess(), false);
DebugAttachedToProcess = false;
DebugAttachedProcessCallBack = NULL;
return &dbgProcessInformation;
}
else
{
DWORD lastError = GetLastError();
if(engineEnableDebugPrivilege)
{
EngineSetDebugPrivilege(GetCurrentProcess(), false);
DebugRemoveDebugPrivilege = false;
}
memset(&dbgProcessInformation, 0, sizeof(PROCESS_INFORMATION));
SetLastError(lastError);
return 0;
}
}

Veo que le da o le quita privilegios justo después de crear el proceso.

aguml
21-05-2020, 22:23:18
Veo que tanto para enviar cómo leer el context suspende antes el thread y después lo revive:
if(SuspendThread(hActiveThread) == (DWORD) - 1)
return false;

returnf = _GetFullContextDataEx(hActiveThread, titcontext, true);

ResumeThread(hActiveThread);

Podría ser por eso que me deniegue el acceso ¿verdad?

aguml
23-05-2020, 00:54:24
Bueno, después de mucho investigar he conseguido aprender cómo configurar el proyecto para que se lance como administrador y así poder obtener privilegios de depurador después y he estado haciendo pruebas y buscando información sobre el context. Sé que tiene que alinearse a 16 bytes y en winnt.h tengo esto:

typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
...
...
Yo después declaro así:
CONTEXT con;
¿Tengo que hacer algo más para que esté bien alineada? A todas las personas que le pasó era por el tema de la alineación de la estructura pero o eran en otro lenguaje o no especifican como arreglaron esto.

aguml
23-05-2020, 11:16:51
He mirado en winnt como define DECLSPEC_ALIGN(n) y vi esto:

#ifndef DECLSPEC_ALIGN
#if (_MSC_VER >= 1300) && !defined(MIDL_PASS) && !defined(__CODEGEARC__)
#define DECLSPEC_ALIGN(x) __declspec(align(x))
#elif defined(__clang__) && !defined(MIDL_PASS)
#define DECLSPEC_ALIGN(x) __attribute__((aligned(x)))
#else
#define DECLSPEC_ALIGN(x)
#endif
#endif

Así que para probar si el problema podía venir por ahí he hecho esto antes de usar la cabecera winnt.h:

#ifndef THiloDebuggerH
#define THiloDebuggerH
//---------------------------------------------------------------------------

#ifdef DECLSPEC_ALIGN
#undef DECLSPEC_ALIGN
#endif
#define DECLSPEC_ALIGN
#define DECLSPEC_ALIGN(x) __declspec(align(x))

#include <Classes.hpp>
#include <winnt.h>
#include <SyncObjs.hpp>


Pero aun con esto me sigue dando el mismo error :(. Ya no se que mas mirar :confused:
Entonces coloqué el siguiente codigo antes de la cabecera de winnt.h:

#if (_MSC_VER >= 1300) && !defined(MIDL_PASS) && !defined(__CODEGEARC__)
#define VALOR 1
#elif defined(__clang__) && !defined(MIDL_PASS)
#define VALOR 2
#else
#define VALOR 3
#endif

Y mi sorpresa es que me muestra el 2 aunque yo lo haya definido antes así que hice esto:

#define _MSC_VER 1300
#undef MIDL_PASS
#undef __CODEGEARC__
Y ahora me muestra el 1 pero ni así consigo librarme del error 998.

Necesito vuestra ayuda :p

aguml
23-05-2020, 11:45:07
Perdón pero me di cuenta que el compilador me lanzaba Warnings y vi que estaba redefiniendo la constante así que la dejé así:
#ifdef DECLSPEC_ALIGN
#undef DECLSPEC_ALIGN
#endif
#define DECLSPEC_ALIGN(x) __declspec(align(x))

Ya no me da Warnings pero sigue dando el mismo error 998 :(

aguml
24-05-2020, 07:38:54
Al final di con el problema. El código era el de x86 y lo estaba adaptando a x64, pues bien, la dichosa estructura en x86 tiene que estar alineada a 8 bytes y para ello antes de la declaración de la clase había un pragma pack(push,8) y al final estaba su respectivo pragma pop con lo que quitando ambas ya fubciona y me deja depurar y ahora toca ir viendo los fallos que vayan saliendo.