View previous topic :: View next topic |
Author |
Message |
yeswejam How do I cheat? Reputation: 0
Joined: 13 Feb 2020 Posts: 6
|
Posted: Thu Feb 13, 2020 2:47 am Post subject: Porting CEServer for Win64 | CMD_WAITFORDEBUGEVENT |
|
|
Hello,
i'm currently working on a Win64 version of the Remote Debugging server and have a question.
I got stuck at the CMD_WAITFORDEBUGEVENT API.
I can successfully create a Debugging Session via WinAPI calls:
DEBUG_EVENT DebugEvent;
DebugActiveProcess(process.pid);
WaitForDebugEvent(&DebugEvent, Timeout)
My Problem: The Client hangs and never responds when responding and sending data back to the API CMD_WAITFORDEBUGEVENT Call
The Client expects following structure;
Code: |
typedef struct {
int debugevent;
int64_t threadid;
union
{
uint64_t
struct {
uint8_t maxBreakpointCount;
uint8_t maxWatchpointCount;
uint8_t maxSharedBreakpoints;
};
};
} DebugEvent, *PDebugEvent;
|
When the WinAPI schedules the ProcessCreated event, i fill the DebugEvent.debugevent member with an signed int of "-2"
When the WinAPI schedules the ThreadCreated event, i fill the DebugEvent.debugevent member with an signed int of "-1"
Code: | // send when WinAPI schedules ProcessCreated or ThreadCreated
// if ProcessCreated then debugevent = -2
// if ThreadCreated then debugevent = -1
*( int32_t*)(writeBuffer->bytes ) = (int32_t) -2;
*(uint64_t*)(writeBuffer->bytes + 4 ) = (uint64_t) DebugEvt.dwThreadId;
// send this extended part if the WinAPI schedules ProcessCreated
*(uint64_t*)(writeBuffer->bytes + 12) = (uint64_t) DebugEvt.u.CreateProcessInfo.lpThreadLocalBase;
*( uint8_t*)(writeBuffer->bytes + 20) = ( uint8_t) 4;
*( uint8_t*)(writeBuffer->bytes + 21) = ( uint8_t) 4;
*( uint8_t*)(writeBuffer->bytes + 22) = ( uint8_t) 4; |
I have tried alot but i never get a feedback back from the Client.
What is wrong here?
The following API's are implemented and the server is running fast, stable and without leaks
Code: | CMD_GETVERSION
CMD_CLOSECONNECTION
CMD_TERMINATESERVER
CMD_OPENPROCESS
CMD_CREATETOOLHELP32SNAPSHOT
CMD_PROCESS32FIRST
CMD_PROCESS32NEXT
CMD_CLOSEHANDLE
CMD_VIRTUALQUERYEX
CMD_READPROCESSMEMORY
CMD_WRITEPROCESSMEMORY
CMD_STARTDEBUG
CMD_STOPDEBUG
CMD_GETARCHITECTURE
CMD_MODULE32FIRST
CMD_MODULE32NEXT
CMD_GETSYMBOLLISTFROMFILE
CMD_LOADEXTENSION
CMD_ALLOC
CMD_FREE
CMD_CREATETHREAD
CMD_VIRTUALQUERYEXFULL
CMD_GETREGIONINFO
CMD_GETHEAPLIST
|
These API's are leftover
Code: | CMD_WAITFORDEBUGEVENT
CMD_CONTINUEFROMDEBUGEVENT
CMD_SETBREAKPOINT
CMD_REMOVEBREAKPOINT
CMD_SUSPENDTHREAD
CMD_RESUMETHREAD
CMD_GETTHREADCONTEXT
CMD_SETTHREADCONTEXT
CMD_AOBSCAN
CMD_LOADMODULE
CMD_SPEEDHACK_SETSPEED |
Last edited by yeswejam on Mon Feb 24, 2020 7:23 pm; edited 1 time in total |
|
Back to top |
|
|
Dark Byte Site Admin Reputation: 457
Joined: 09 May 2003 Posts: 25262 Location: The netherlands
|
Posted: Thu Feb 13, 2020 4:56 am Post subject: |
|
|
So it doesn't call CMD_CONTINUEFROMDEBUGEVENT pretty much immediately after the CMD_WAITFORDEBUGEVENT call?
is your debugging session running in a new thread? (It should be as it created a new socket, but just making sure you didn't group it into one thread for some kind of optimization reason)
perhaps your writeBuffer isn't correct, it should be 20 bytes long
for createProcess it's only debugeventnr, threadid, maxBreakpointCount, maxWatchpointCount, maxSharedBreakpoints
no DebugEvt.u.CreateProcessInfo.lpThreadLocalBase for createProcess
only for signal 5 (single step) you provide the address that triggered it (but then no max* ) _________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
Back to top |
|
|
yeswejam How do I cheat? Reputation: 0
Joined: 13 Feb 2020 Posts: 6
|
Posted: Thu Feb 13, 2020 6:01 am Post subject: |
|
|
I handle every socket connection in a new Thread and keep each alive until the client socket disconnects explicitly and free the resources then.
It worked well so far.
See Attachment #1
Once the client sends CMD_STARTDEBUG and my dispatcher calls __StartDebug, i mark the current socket thread as DebuggerThread for the rest of the persistent connection.
See Attachment #2
I have not noticed that CMD_CONTINUEFROMDEBUGEVENT got called right after. gotta check it later again. |
|
Back to top |
|
|
Dark Byte Site Admin Reputation: 457
Joined: 09 May 2003 Posts: 25262 Location: The netherlands
|
Posted: Thu Feb 13, 2020 3:19 pm Post subject: |
|
|
yeswejam wrote: | I can't double post yet.
when i send 14 bytes twice before the synchronized recv(), the client responds with the CMD_CONTINUEFROMDEBUGEVENT command Call
*( int32_t*)(writeBuffer->bytes ) = -2;
*(uint64_t*)(writeBuffer->bytes + 4 ) = DebugEvt.dwThreadId;
*( uint8_t*)(writeBuffer->bytes + 12) = 0;
*( uint8_t*)(writeBuffer->bytes + 13) = 0;
*( uint8_t*)(writeBuffer->bytes + 14) = 4;
i don't know why it has to be two calls but as long it's consistent, i don't care
Thanks Darkbyte |
As I mentioned in the previous reply, your createprocess command was wrong
The 3th field of the debugevent is a union, not a record, so it's EITHER a debug address(for single step) OR or debugger capabilities(for new process) or else filler(for new thread)
make sure you send exactly 20 (0x14) bytes.
seeing you use visual studio, try this one instead:
Code: |
#pragma pack (1)
typedef struct {
int debugevent;
int64_t threadid;
union
{
uint64_t address;
struct {
uint8_t maxBreakpointCount;
uint8_t maxWatchpointCount;
uint8_t maxSharedBreakpoints;
};
};
} DebugEvent, *PDebugEvent;
#pragma pack()
|
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
Back to top |
|
|
yeswejam How do I cheat? Reputation: 0
Joined: 13 Feb 2020 Posts: 6
|
Posted: Thu Feb 13, 2020 9:00 pm Post subject: |
|
|
Alright.
Just to make it sure and there is no misunderstanding.
So essentially there are only 3 events which should care the DebuggerThread and the WaitForDebugEvent API.
1. CREATE_PROCESS_DEBUG_EVENT
Code: | DebugEvent devent;
memset(&devent,0, sizeof(DebugEvent));
devent.debugevent = -2
devent.threadid = threadId
devent.maxBreakpointCount = 0;
devent.maxWatchpointCount = 0;
devent.maxSharedBreakpoints = 4;
send(&devent,20); |
3. CREATE_THREAD_DEBUG_EVENT
Code: | DebugEvent devent;
memset(&devent,0, sizeof(DebugEvent));
devent.debugevent = -1
devent.threadid = threadId
send(&devent,20); |
3. EXCEPTION_DEBUG_EVENT
Code: | DebugEvent devent;
memset(&devent,0, sizeof(DebugEvent));
devent.debugevent = SIGTRAP // 5
devent.threadid = threadId
devent.address = address of exception event
send(&devent,20); |
This data is enough information for the Client to advance.
So is the DebuggerThread dedicated to following 4 CEServer API's ?
CMD_STARTDEBUG
CMD_STOPDEBUG
CMD_WAITFORDEBUGEVENT
CMD_CONTINUEFROMDEBUGEVENT
or should it also invoke the 6 API's below and give feedback to the Client DebuggerSocket ?
CMD_SETBREAKPOINT
CMD_REMOVEBREAKPOINT
CMD_SUSPENDTHREAD
CMD_RESUMETHREAD
CMD_GETTHREADCONTEXT
CMD_SETTHREADCONTEXT
Is the Client DebuggerSocket directly sending commands or do all other connections schedule Jobs for the DebuggerThread by pushing Tasks to a list??
The whole remote debug workflow is making more sense for me now and i'm not as trapped in the dark as i was 48hours ago.
Thank you for your time, though. |
|
Back to top |
|
|
Dark Byte Site Admin Reputation: 457
Joined: 09 May 2003 Posts: 25262 Location: The netherlands
|
Posted: Fri Feb 14, 2020 2:11 am Post subject: |
|
|
only the debugger socket should send debug loop messages, but other threads(/sockets) can call the other API commands
anyhow, just deal with the command in the thread/socket it arrives on.
Unlike android/linux when a process is debugged you don't need to go through the debuggerthread to read memory from that point, so no special handling is needed here _________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping
Last edited by Dark Byte on Fri Feb 14, 2020 2:19 am; edited 1 time in total |
|
Back to top |
|
|
yeswejam How do I cheat? Reputation: 0
Joined: 13 Feb 2020 Posts: 6
|
Posted: Fri Feb 14, 2020 2:15 am Post subject: |
|
|
Thank you for the Infos
Should be everything clear now. |
|
Back to top |
|
|
yeswejam How do I cheat? Reputation: 0
Joined: 13 Feb 2020 Posts: 6
|
Posted: Sat Feb 15, 2020 9:33 pm Post subject: |
|
|
I need help again @ GetThreadContext
Despite sending from the DebuggerEvent CreateProcess the number of breakpoints.
devent.debugevent = -2;
devent.threadId = DebugEvt.dwThreadId;
devent.maxBreakpointCount = 4;
devent.maxWatchpointCount = 4;
devent.maxSharedBreakpoints = 4;
I always get an Error from the client: "All debug registers are used up and this debugger interface does not support software Breakpoints. Remove some and try again"
I've defined the linux x86_64 usermode thread context struct and map the win64 thread context to it and send it to the client.
Code: |
struct user_regs_struct
{
__extension__ unsigned long long int r15;
__extension__ unsigned long long int r14;
__extension__ unsigned long long int r13;
__extension__ unsigned long long int r12;
__extension__ unsigned long long int rbp;
__extension__ unsigned long long int rbx;
__extension__ unsigned long long int r11;
__extension__ unsigned long long int r10;
__extension__ unsigned long long int r9;
__extension__ unsigned long long int r8;
__extension__ unsigned long long int rax;
__extension__ unsigned long long int rcx;
__extension__ unsigned long long int rdx;
__extension__ unsigned long long int rsi;
__extension__ unsigned long long int rdi;
__extension__ unsigned long long int orig_rax;
__extension__ unsigned long long int rip;
__extension__ unsigned long long int cs;
__extension__ unsigned long long int eflags;
__extension__ unsigned long long int rsp;
__extension__ unsigned long long int ss;
__extension__ unsigned long long int fs_base;
__extension__ unsigned long long int gs_base;
__extension__ unsigned long long int ds;
__extension__ unsigned long long int es;
__extension__ unsigned long long int fs;
__extension__ unsigned long long int gs;
};
|
Commented the line where i get the Error.
Code: |
ctx.ContextFlags = CONTEXT_ALL;
if (result = GetThreadContext(threadHandle, &ctx)) {
lctx.regs.eflags = static_cast<u64>(ctx.EFlags);
lctx.regs.ss = static_cast<u64>(0);
lctx.regs.cs = static_cast<u64>(ctx.SegCs);
lctx.regs.ds = static_cast<u64>(ctx.SegDs);
lctx.regs.es = static_cast<u64>(ctx.SegEs);
lctx.regs.fs = static_cast<u64>(ctx.SegFs);
lctx.regs.gs = static_cast<u64>(ctx.SegGs);
lctx.regs.fs_base = static_cast<u64>(ctx.SegFs);
lctx.regs.gs_base = static_cast<u64>(ctx.SegGs);
lctx.regs.orig_rax= static_cast<u64>(ctx.Rax);
lctx.regs.rax = static_cast<u64>(ctx.Rax);
lctx.regs.rbx = static_cast<u64>(ctx.Rbx);
lctx.regs.rcx = static_cast<u64>(ctx.Rcx);
lctx.regs.rdx = static_cast<u64>(ctx.Rdx);
lctx.regs.rdi = static_cast<u64>(ctx.Rdi);
lctx.regs.rdx = static_cast<u64>(ctx.Rdx);
lctx.regs.rip = static_cast<u64>(ctx.Rip);
lctx.regs.rsi = static_cast<u64>(ctx.Rsi);
lctx.regs.rbp = static_cast<u64>(ctx.Rbp);
lctx.regs.rsp = static_cast<u64>(ctx.Rsp);
lctx.regs.r8 = static_cast<u64>(ctx.R8);
lctx.regs.r9 = static_cast<u64>(ctx.R9);
lctx.regs.r10 = static_cast<u64>(ctx.R10);
lctx.regs.r11 = static_cast<u64>(ctx.R11);
lctx.regs.r12 = static_cast<u64>(ctx.R12);
lctx.regs.r13 = static_cast<u64>(ctx.R13);
lctx.regs.r14 = static_cast<u64>(ctx.R14);
lctx.regs.r15 = static_cast<u64>(ctx.R15);
u32 _structsize = sizeof(LCONTEXT);
printf("result: %d\n structsize: %d\n, Contextsize: %d\n", result, sizeof(_structsize), _structsize);
if (!isDebuggerThread) {
DebuggerSocket->lock();
DebuggerSocket->send(>c, sizeof(gtc));
DebuggerSocket->recvall(&result, 4);
DebuggerSocket->recvall(&_structsize, 4);
DebuggerSocket->recvall(&lctx.regs, _structsize);
DebuggerSocket->unlock();
}
else {
DebuggerSocket->send(&result, 4);
DebuggerSocket->send(&_structsize, 4);
DebuggerSocket->send(&lctx.regs, _structsize); // After this transmit, the client gives the Error
}
}
|
|
|
Back to top |
|
|
Dark Byte Site Admin Reputation: 457
Joined: 09 May 2003 Posts: 25262 Location: The netherlands
|
Posted: Sun Feb 16, 2020 2:02 am Post subject: |
|
|
set maxBreakpointCount and maxWatchpointCount to 0
also no need to do that if (!isDebuggerThread) thing in windows
i don't know how send is implemented in your case but I think that may go bad if that send goes to the client as it's on the wrong socket that's not listening for a result
in windows just use the socket that initates the command _________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
Back to top |
|
|
yeswejam How do I cheat? Reputation: 0
Joined: 13 Feb 2020 Posts: 6
|
Posted: Sun Feb 16, 2020 2:49 am Post subject: |
|
|
followed the suggestions, but still get the same result.
the user_reg_struct seems to be ok, because the client lists the remote thread registers fine. |
|
Back to top |
|
|
|