|
|
dd89bb |
/********************************************************/
|
|
|
dd89bb |
/* ntapi: Native API core library */
|
|
|
dde53a |
/* Copyright (C) 2013--2017 Z. Gilboa */
|
|
|
dd89bb |
/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
|
|
|
dd89bb |
/********************************************************/
|
|
|
dd89bb |
|
|
|
dd89bb |
#include <psxtypes/psxtypes.h>
|
|
|
dd89bb |
#include <ntapi/ntapi.h>
|
|
|
dd89bb |
#include "ntapi_impl.h"
|
|
|
dd89bb |
|
|
|
dd89bb |
/************************************************************/
|
|
|
dd89bb |
/* beginning with version 6.0, explicit thread registration */
|
|
|
dd89bb |
/* with csrss is no longer required. the code below should */
|
|
|
dd89bb |
/* work with all known versions of NT, however it will only */
|
|
|
dd89bb |
/* be used when run on the now-obsolete versions of the OS. */
|
|
|
dd89bb |
/************************************************************/
|
|
|
dd89bb |
|
|
|
dd89bb |
/**
|
|
|
dd89bb |
Nebbett was pretty much right in his interpretation of
|
|
|
dd89bb |
the csrss port message; and as long as one changes
|
|
|
dd89bb |
uint32_t to uintptr_t (especially when it comes to the
|
|
|
dd89bb |
unknown parameters), then the structures behave as
|
|
|
dd89bb |
expected according to his book.
|
|
|
dd89bb |
|
|
|
dd89bb |
SysInternals: ProcessExplorer: csrss.exe: the stack shows
|
|
|
dd89bb |
a thread in csrsrv.dll that has CsrUnhandledExceptionFilter
|
|
|
dd89bb |
as its start address, and ntdll!NtReplyWaitReceivePort as
|
|
|
dd89bb |
its next function call. This suggests that csrss still
|
|
|
dd89bb |
uses LPC (at least to some extent) for communication with
|
|
|
dd89bb |
user processes.
|
|
|
dd89bb |
|
|
|
dd89bb |
Given the above, we may deduce that CsrClientCallServer
|
|
|
dd89bb |
contains a call to ZwRequestWaitReplyPort. Assuming
|
|
|
dd89bb |
the machine code in ntdll is as optimized as possible,
|
|
|
dd89bb |
we may then conclude that on x86 machines, this would be
|
|
|
dd89bb |
an E8 call using relative 32-bit addressing on both NT32
|
|
|
dd89bb |
and NT64.
|
|
|
dd89bb |
|
|
|
dd89bb |
On the 32-bit variant of the operating system, the first
|
|
|
dd89bb |
argument is passed on the stack, and is normally expressed
|
|
|
dd89bb |
in terms of an offset from the ds register.
|
|
|
dd89bb |
|
|
|
dd89bb |
On the 64-bit variant of the operating system, the first
|
|
|
dd89bb |
argument is passed in the rcx register. Here, again,
|
|
|
dd89bb |
machine code optimization suggests that the address of
|
|
|
dd89bb |
CsrPortHandle will be provided as a 32-bit relative address,
|
|
|
dd89bb |
or else the code will be larger by several bytes.
|
|
|
dd89bb |
|
|
|
dd89bb |
The rest is based on simple logic and straight-forward
|
|
|
dd89bb |
heuristics. Since we know the addresses of CsrClientCallSertver
|
|
|
dd89bb |
and ZwRequestWaitReplyPort, we first find the call to the latter
|
|
|
dd89bb |
function within the former. Once we have found that call, we
|
|
|
dd89bb |
start going back to look for the argument-passing
|
|
|
dd89bb |
opcode, and finally do the math to obtain the address of
|
|
|
dd89bb |
CsrPortHandle.
|
|
|
dd89bb |
**/
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
#if defined(__X86_MODEL)
|
|
|
dd89bb |
void ** __cdecl __ntapi_tt_get_csr_port_handle_addr_by_logic_i386(void)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
#define MAX_BYTES_BETWEEN_ARG1_PUSH_AND_E8_CALL 0x20
|
|
|
dd89bb |
#define MAX_FN_BYTES_TO_TEST 0x800
|
|
|
dd89bb |
|
|
|
dd89bb |
typedef struct __attr_aligned__ (1) __attr_packed__ __x86_e8_call_signature {
|
|
|
dd89bb |
unsigned char __opcode_current_e8;
|
|
|
dd89bb |
unsigned char __addr_relative[4];
|
|
|
dd89bb |
unsigned char __opcode_next_any;
|
|
|
dd89bb |
} _x86_e8_call_signature;
|
|
|
dd89bb |
|
|
|
dd89bb |
typedef struct __attr_aligned__ (1) __attr_packed__ __x86_push_ds_signature {
|
|
|
dd89bb |
unsigned char __push;
|
|
|
dd89bb |
unsigned char __ds;
|
|
|
dd89bb |
unsigned char __push_ds_arg;
|
|
|
dd89bb |
} _x86_push_ds_signature;
|
|
|
dd89bb |
|
|
|
dd89bb |
unsigned char * ptr_test;
|
|
|
dd89bb |
_x86_e8_call_signature * ptr_e8_call;
|
|
|
dd89bb |
_x86_push_ds_signature * ptr_push_ds;
|
|
|
dd89bb |
int32_t offset;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* type-punned tyrants */
|
|
|
dd89bb |
int32_t * prelative;
|
|
|
dd89bb |
int32_t relative;
|
|
|
dd89bb |
uintptr_t * pport_addr;
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
/* calling a function within the same library: assume E8 call */
|
|
|
dd89bb |
for (offset = 0; offset < MAX_FN_BYTES_TO_TEST; offset++) {
|
|
|
dd89bb |
ptr_test = (unsigned char *)__ntapi->csr_client_call_server
|
|
|
dd89bb |
+ offset;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (*ptr_test == 0xE8) {
|
|
|
dd89bb |
ptr_e8_call = (_x86_e8_call_signature *)ptr_test;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* make our type-punned tyrant compiler happy */
|
|
|
dd89bb |
prelative = (int32_t *)&(ptr_e8_call->__addr_relative);
|
|
|
dd89bb |
relative = *prelative;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* are we calling ZwRequestWaitReplyPort? */
|
|
|
dd89bb |
if ((uintptr_t)(__ntapi->zw_request_wait_reply_port) ==
|
|
|
dd89bb |
(uintptr_t)&(ptr_e8_call->__opcode_next_any)
|
|
|
dd89bb |
+ relative) {
|
|
|
dd89bb |
/* assume ds relative address for arg1, go back to find it */
|
|
|
dd89bb |
for (offset = 0; offset < MAX_BYTES_BETWEEN_ARG1_PUSH_AND_E8_CALL; offset++) {
|
|
|
dd89bb |
ptr_push_ds = (_x86_push_ds_signature *)((uintptr_t)ptr_e8_call - offset);
|
|
|
dd89bb |
|
|
|
dd89bb |
if ((ptr_push_ds->__push == 0xFF) &&
|
|
|
dd89bb |
(ptr_push_ds->__ds == 0x35)) {
|
|
|
dd89bb |
/* bingo */
|
|
|
dd89bb |
/* make our type-punned tyrant compiler happy */
|
|
|
dd89bb |
pport_addr = (uintptr_t *)&(ptr_push_ds->__push_ds_arg);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* all done */
|
|
|
dd89bb |
return *(void ***)pport_addr;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* CsrPortHandle not found */
|
|
|
dd89bb |
return (void **)0;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
#endif
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
#if defined(__X86_64_MODEL)
|
|
|
dd89bb |
void ** __ntapi_tt_get_csr_port_handle_addr_by_logic_x86_64(void)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
#define MAX_BYTES_BETWEEN_ARG1_PUSH_AND_E8_CALL 0x20
|
|
|
dd89bb |
#define MAX_FN_BYTES_TO_TEST 0x800
|
|
|
dd89bb |
|
|
|
dd89bb |
typedef struct __attr_aligned__ (1) __attr_packed__ __x86_e8_call_signature {
|
|
|
dd89bb |
unsigned char __opcode_current_e8;
|
|
|
dd89bb |
unsigned char __addr_relative[4];
|
|
|
dd89bb |
unsigned char __opcode_next_any;
|
|
|
dd89bb |
} _x86_e8_call_signature;
|
|
|
dd89bb |
|
|
|
dd89bb |
typedef struct __attr_aligned__ (1) __attr_packed__ __x86_move_rcx_rel_signature {
|
|
|
dd89bb |
unsigned char __move;
|
|
|
dd89bb |
unsigned char __rcx;
|
|
|
dd89bb |
unsigned char __relative;
|
|
|
dd89bb |
unsigned char __arg_32_relative[4];
|
|
|
dd89bb |
unsigned char __opcode_next_any;
|
|
|
dd89bb |
} _x86_move_rcx_rel_signature;
|
|
|
dd89bb |
|
|
|
dd89bb |
unsigned char * ptr_test;
|
|
|
dd89bb |
_x86_e8_call_signature * ptr_e8_call;
|
|
|
dd89bb |
_x86_move_rcx_rel_signature * ptr_move_rcx_rel;
|
|
|
dd89bb |
int32_t offset;
|
|
|
dd89bb |
int32_t relative;
|
|
|
439a91 |
int32_t * prelative;
|
|
|
439a91 |
int bias;
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
/* calling a function within the same library: assume E8 call and 32-bit relative addressing */
|
|
|
439a91 |
for (bias = 0; bias < MAX_FN_BYTES_TO_TEST; bias++) {
|
|
|
439a91 |
ptr_test = (unsigned char *)__ntapi->csr_client_call_server;
|
|
|
439a91 |
ptr_test += bias;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (*ptr_test == 0xE8) {
|
|
|
dd89bb |
ptr_e8_call = (_x86_e8_call_signature *)ptr_test;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* please our type-punned tyrant compiler */
|
|
|
dd89bb |
prelative = (int32_t *)&(ptr_e8_call->__addr_relative);
|
|
|
dd89bb |
relative = *prelative;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* are we calling ZwRequestWaitReplyPort? */
|
|
|
dd89bb |
/* comparing, not writing; ignore type-punned msgs. */
|
|
|
dd89bb |
if ((uintptr_t)(__ntapi->zw_request_wait_reply_port) ==
|
|
|
dd89bb |
(uintptr_t)&(ptr_e8_call->__opcode_next_any)
|
|
|
dd89bb |
+ relative) {
|
|
|
dd89bb |
/* arg1 must be passed in rcx, so go back to find it */
|
|
|
dd89bb |
for (offset = 0; offset < MAX_BYTES_BETWEEN_ARG1_PUSH_AND_E8_CALL; offset++) {
|
|
|
dd89bb |
ptr_move_rcx_rel = (_x86_move_rcx_rel_signature *)((uintptr_t)ptr_e8_call - offset);
|
|
|
dd89bb |
|
|
|
dd89bb |
if ((ptr_move_rcx_rel->__move == 0x48) &&
|
|
|
dd89bb |
(ptr_move_rcx_rel->__rcx == 0x8b) &&
|
|
|
767992 |
(ptr_move_rcx_rel->__relative == 0x0d)) {
|
|
|
dd89bb |
/* bingo */
|
|
|
dd89bb |
/* make our type-punned tyrant compiler happy */
|
|
|
dd89bb |
prelative = (int32_t *)&(ptr_move_rcx_rel->__arg_32_relative);
|
|
|
dd89bb |
relative = *prelative;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* all done */
|
|
|
dd89bb |
return (void **)(
|
|
|
dd89bb |
(uintptr_t)&ptr_move_rcx_rel->__opcode_next_any
|
|
|
dd89bb |
+ relative);
|
|
|
767992 |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* CsrPortHandle not found */
|
|
|
439a91 |
return 0;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
#endif
|