不完全类型检测 “typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];”

最近在关注Boost库中智能指针的相关知识,剖析到下面的一段代码,在头文件checked_delete.hpp中的用于释放空间的类模板函
checked_array_delete(T * x);:

template<class T> inline void checked_array_delete(T * x)  
{  
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];  
    (void) sizeof(type_must_be_complete);  
    delete [] x;  
}  

代码很简单,但表达的东西却很隐晦,其实这是一种不完全类型检测:T如果不是不完全类型那么sizeof(T)就应该是type_must_be_complete[-1],数组是不能为负数的,所以就会报错;
什么又是不完全类型呢?简单理解就是类型的定义不完整,比如只对类进行了声明,却未定义;


                
#include <string.h> #include <stdlib.h> #include "event2/buffer.h" #include "udp_punch.h" #include "udt_c.h" #include "utils.h" #include "session.h" #ifdef HAVE_VS #include "../include/video_share.h" #endif #define PUNCH_SYN_SENT 1 #define PUNCH_SYN_RCVD 2 #define PUNCH_SYNACK_RCVD 3 #define PUNCH_UDT_CONNECTED 4 #define PUNCH_OPT_ACK 0x00000001 #ifndef PUNCH_PREPARING_TTL #define PUNCH_PREPARING_TTL 5 #endif /* private IP range -- RFC1918 * 10.0.0.0/8 * 172.16.0.0/12 * 192.168.0.0/16 */ #define PRIVATE_NIPV4(__nip) (((__nip)&0x000000FF) == 0x0000000A || \ ((__nip)&0x0000F0FF) == 0x000010AC || \ ((__nip)&0x0000FFFF) == 0x0000A8C0) #define UDT_SNDBUF_SIZE (256*1024) #define UDT_RCVBUF_SIZE (16*1024) #define UDT_MAX_SEG_SIZE 1420 #ifndef UDT_SNDLOWAT #define UDT_SNDLOWAT 1 #endif typedef struct punch_inner_data_s { struct event* evstun; /* event for UDP */ struct sockaddr_in sin_peer; /* peer address */ int status; int punch_prepared; int punch_try_cnt; int fd_udt; unsigned int udt_sndlowat; struct evbuffer* evbuf_out; } punch_inner_data_t; static const char* _sockaddr_ntoa(const struct sockaddr_in* sin) { static char s[32]; snprintf(s, sizeof(s), "%s:%d", inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); return s; } static int stun_udtsyn(void* data, int size) { /* TODO: udt v4 */ static const char* udt4_syn = "\x80\x00\x00\x00" "\x00\x00\x00\x00" "\x00\x00\x00\x00" "\x00\x00\x00\x00" "\x00\x00\x00\x04"; if ( size >= 20 && !memcmp(data, udt4_syn, 20) ) { return 1; } return 0; } static int udt_get_state(int fd_udt) { int state = BROKEN, len; len = sizeof(state); if( udt_getsockopt(fd_udt, 0, UDT_STATE, &state, &len) ) { return BROKEN; } return state; } static int udt_get_canrecv(int fd_udt) { int canrecv = -1, len; len = sizeof(canrecv); if( udt_getsockopt(fd_udt, 0, UDT_RCVDATA, &canrecv, &len) ) { return -1; } return canrecv; } static int udt_get_cansend(int fd_udt) { int sendbufused, len; len = sizeof(sendbufused); if( udt_getsockopt(fd_udt, 0, UDT_SNDDATA, &sendbufused, &len) ) { return -1; } return UDT_SNDBUF_SIZE - sendbufused*UDT_MAX_SEG_SIZE; } static int build_udt_socket(int fd_udp, int rendezvous, int without_linger) { UDTSOCKET fd_udt; int opt, ret = 0; fd_udt = udt_socket(PF_INET, SOCK_STREAM, 0); if ( -1 == fd_udt ) { DBG_LOG(DBG_ERR, "udt_socket failed, errcode %d\n", udt_getlasterror_code()); return -1; } /* set socket options: RENDEZVOUS, MSS, NONBLOCK, SND/RCV BUFFER size. */ opt = 1; if ( rendezvous ) { ret = udt_setsockopt(fd_udt, 0, UDT_RENDEZVOUS, &opt, sizeof(opt)); } if ( without_linger ) { struct linger lg; lg.l_onoff = 0; lg.l_linger = 0; DBG_LOG(DBG_ERR, "udt socket without linger\n"); ret = ret ? ret : udt_setsockopt(fd_udt, 0, UDT_LINGER, &lg, sizeof(lg)); } opt = UDT_MAX_SEG_SIZE; /* strips headers (PPPOE, PPP, ...) off */ ret = ret ? ret : udt_setsockopt(fd_udt, 0, UDT_MSS, &opt, sizeof(opt)); opt = 0; ret = ret ? ret : udt_setsockopt(fd_udt, 0, UDT_RCVSYN, &opt, sizeof(opt)); if ( ret != 0 ) { DBG_LOG(DBG_ERR, "udt_setsockopt failed, errcode %d\n", udt_getlasterror_code()); udt_close(fd_udt); return -1; } /* set socket buffer size */ opt = UDT_SNDBUF_SIZE; udt_setsockopt(fd_udt, 0, UDT_SNDBUF, &opt, sizeof(opt)); opt >>= 1; udt_setsockopt(fd_udt, 0, UDP_SNDBUF, &opt, sizeof(opt)); opt = UDT_RCVBUF_SIZE; udt_setsockopt(fd_udt, 0, UDT_RCVBUF, &opt, sizeof(opt)); opt >>= 1; udt_setsockopt(fd_udt, 0, UDP_RCVBUF, &opt, sizeof(opt)); /* bind to local udp address */ if ( fd_udp != -1 ) { /* FIXME: non-block fd(UDP) makes udt_bind2 crazy!!! */ evutil_make_socket_blocking(fd_udp); if ( udt_bind2(fd_udt, fd_udp) != 0 ) { DBG_LOG(DBG_ERR, "udt_bind2 failed, errcode %d\n", udt_getlasterror_code()); udt_close(fd_udt); return -1; } } return fd_udt; } static int udt_do_send_stream(punch_inner_data_t* inner_ctx) { int ret, sent = 0; int size; char buf[4096] = {0}; do { memset(buf, 0, sizeof(buf)); size = evbuffer_copyout(inner_ctx->evbuf_out, buf, sizeof(buf)); if ( size <= 0 ) { break; } ret = udt_send(inner_ctx->fd_udt, buf, size, 0); if ( -1 == ret ) { if (udt_getlasterror_code() == EASYNCSND ) { return 0; } else { DBG_LOG(DBG_ERR, "udt_send failed, errcode %d\n", udt_getlasterror_code()); return -1; } } evbuffer_drain(inner_ctx->evbuf_out, ret); sent += ret; /* send not complete, or buffer empty */ if ( ret < size || size < sizeof(buf) ) { break; } } while (1); return sent; } #ifdef HAVE_VS #define HTTP_RESPONSE_503_6 \ "HTTP/1.0 503.6 Service Unavailable\r\n"\ "Server: p2pd\r\n"\ "Content-Length: 0\r\n"\ "Content-Type: text/html\r\n"\ "Connection: close\r\n"\ "\r\n" #endif static int read_local_data(punch_ctx_t *ctx) { punch_inner_data_t* inner_ctx = ctx->inner_data; char buf[8192]; int buf_size = sizeof(buf); int ret = 0; int avail_buf_size = 0; int iter_size = 0; int recv_size_from_local = 0; int send_size = 0; if (!ctx->test_local_server(ctx->env)) { return 0; } while (1) { avail_buf_size = udt_get_cansend(inner_ctx->fd_udt); if (avail_buf_size <= 0) { break; } iter_size = (avail_buf_size > buf_size)?buf_size:avail_buf_size; recv_size_from_local = ctx->read_from_local_server(ctx->env, (void *)buf, iter_size); if (recv_size_from_local < 0) { DBG_LOG(DBG_ERR, "recv data from local server failed.\n"); return -1; } if (recv_size_from_local == 0) { break; } ret = udt_send(inner_ctx->fd_udt, buf, recv_size_from_local, 0); if (ret < 0) { return -1; } } return 0; } #ifdef ADD_REMOTE_ADDR static int add_header_to_evbuf(session_t *sess, char *buf, int len) { if (sess->evbuf_in == NULL) { sess->evbuf_in = evbuffer_new(); if (NULL == sess->evbuf_in) { return -1; } } if (HTTP_HEADER_MAX_LEN <= evbuffer_get_length(sess->evbuf_in)) { DBG_LOG(DBG_ERR, "http header is too long.\n"); return -1; } evbuffer_add(sess->evbuf_in, buf, len); return 0; } static int evbuf_contain_complete_header(struct evbuffer *evbuf) { char *header_end = NULL; int buf_len = 0; if (NULL == evbuf) { /* false */ return FALSE; } header_end = evbuffer_find(evbuf, "\r\n\r\n", 4); if (NULL == header_end) { DBG_LOG(DBG_ERR, "http header is too long\n"); return FALSE; } return TRUE; } static int send_new_header(session_t *sess) { int ret = 0; char *header_end = NULL; int header_len = 0; char buf[HTTP_HEADER_MAX_LEN + 1] = {0}; punch_ctx_t *ctx = &sess->punch_ctx; ret = evbuffer_copyout(sess->evbuf_in, buf, sizeof(buf) - 1); if (ret <= 0) { return -1; } header_end = strstr(buf, "\r\n\r\n"); if (NULL == header_end) { return -1; } /* add \r\n */ header_end += 2; header_len = header_end - buf; int left_len = sizeof(buf) - header_len; /* �ⲿIP����ȷ���Զ˵ĵ�����ַ */ snprintf(header_end, left_len, "X-Client-Addr: %s\r\n\r\n", sess->prepare_req.eip); if ( ctx->write_to_local_server(ctx->env, buf, strlen(buf)) < 0 ) { return -1; } /* there is a "\r\n" left */ header_len += 2; evbuffer_drain(sess->evbuf_in, header_len); while (0 != evbuffer_get_length(sess->evbuf_in)) { ret = evbuffer_remove(sess->evbuf_in, buf, sizeof(buf) - 1); if (ret <= 0) { return -1; } if (ctx->write_to_local_server(ctx->env, buf, ret) < 0) { return -1; } } evbuffer_free(sess->evbuf_in); sess->evbuf_in = NULL; sess->header_recv = 1; return 0; } #endif static int read_peer_data(punch_ctx_t *ctx) { int ret = 0; punch_inner_data_t* inner_ctx = ctx->inner_data; char buf[2048]; int buf_size = sizeof(buf); session_t* sess = ctx->env; #ifdef HAVE_VS char sndbuf[256 + 1] = {0}; int size = 0; time_t t; #endif #ifdef ADD_REMOTE_ADDR char *new_header = NULL; #endif if(udt_get_canrecv(inner_ctx->fd_udt) <= 0 ) { return 0; } ret = udt_recv(inner_ctx->fd_udt, buf, sizeof(buf), 0); if ( -1 == ret && udt_getlasterror_code() == EASYNCRCV ) { return 0; } if ( ret <= 0 ) { return -1; } #ifdef HAVE_VS /* need to check permission when it is video share */ if(sess->prepare_req.is_video_share) { DBG_LOG(DBG_DBG, "it is video share, need to check permission\n"); t = time(NULL); if(strstr(buf, "/stream") != NULL) { DBG_LOG(DBG_DBG, "this request is POST /stream, now check permission\n"); if(0 == vs_share_rules_time_valid(&t, &sess->share_info->rules)) { DBG_LOG(DBG_ERR, "permission denied, send 503.6 to peer\n"); size = snprintf(sndbuf, 200, HTTP_RESPONSE_503_6); udt_send(inner_ctx->fd_udt, sndbuf, size, 0); return 0; } } else { DBG_LOG(DBG_DBG, "request type is not GET\n"); } DBG_LOG(DBG_DBG, "permission check passed\n"); } #endif #ifdef ADD_REMOTE_ADDR //printf("buf: %s\n", buf); if (!sess->header_recv) { if (0 > add_header_to_evbuf(sess, buf, ret)) { DBG_LOG(DBG_ERR, "failed to add header to evbuf\n"); return -1; } if (!evbuf_contain_complete_header(sess->evbuf_in)) { return 0; } if (0 > send_new_header(sess)) { DBG_LOG(DBG_ERR, "failed to send new header\n"); return -1; } return 0; } #endif if ( ctx->write_to_local_server(ctx->env, buf, ret) < 0 ) { return -1; } return 0; } static void udt_event_cb(evutil_socket_t fd, short events, void* arg) { int ret; punch_ctx_t* ctx = arg; punch_inner_data_t* inner_ctx = ctx->inner_data; int udt_stat = NONEXIST; udt_stat = udt_get_state(inner_ctx->fd_udt); if (udt_stat != CONNECTED) { if ( !(inner_ctx->status & PUNCH_UDT_CONNECTED) ) { return ; } else { DBG_LOG(DBG_ERR, "udt io-error, errcode %d\n", udt_getlasterror_code()); goto FAILED; } } else { if (!(inner_ctx->status & PUNCH_UDT_CONNECTED)) { DBG_LOG(DBG_DBG, "udt_connect OK, peer address: %s\n", _sockaddr_ntoa(&inner_ctx->sin_peer)); inner_ctx->status = PUNCH_UDT_CONNECTED; if ( ctx->succeed_cb(ctx->env, &inner_ctx->sin_peer) < 0 ) { DBG_LOG(DBG_ERR, "udt succeed_cb failed.\n"); goto FAILED; } } } ret = read_peer_data(ctx); if (ret < 0) { DBG_LOG(DBG_ERR, "read_peer_data failed.\n"); goto FAILED; } ret = read_local_data(ctx); if (ret < 0) { DBG_LOG(DBG_ERR, "read_local_data failed.\n"); goto FAILED; } return ; FAILED: ctx->error_cb(ctx->env); } static int udt_async_connect(punch_ctx_t* ctx, int rendezvous, int without_linger) { punch_inner_data_t* inner_ctx = ctx->inner_data; struct timeval tv = {0, 100*1000}; event_del(inner_ctx->evstun); event_assign(inner_ctx->evstun, ctx->base, -1, EV_TIMEOUT|EV_PERSIST, udt_event_cb, ctx); if ( event_add(inner_ctx->evstun, &tv) < 0 ) { return -1; } /* rendezvous */ inner_ctx->fd_udt = build_udt_socket(ctx->fd, rendezvous, without_linger); if ( inner_ctx->fd_udt < 0 ) { return -1; } DBG_LOG(DBG_DBG, "udt connect to %s...\n", _sockaddr_ntoa(&inner_ctx->sin_peer)); return udt_connect(inner_ctx->fd_udt, (void*)&inner_ctx->sin_peer, sizeof(inner_ctx->sin_peer)); } static int stun_send_syn(punch_ctx_t* ctx, int opt) { punch_inner_data_t* inner_ctx = ctx->inner_data; struct sockaddr_in sin, sin2; char buf[512]; int ret = 0, len, i; snprintf(buf, sizeof(buf), "%s", ctx->stun_sid); if ( (opt & PUNCH_OPT_ACK) ) { buf[0]++; } len = (int)strlen(buf) + 1; sin = (opt & PUNCH_OPT_ACK) ? inner_ctx->sin_peer : ctx->sin_peer_wan; DBG_LOG(DBG_DBG, "punch buffer is %s\n", buf); // port = ntohs(sin.sin_port); //TODO: port prediction //PRINTF("sending %s...\n", (opt & PUNCH_OPT_ACK) ? "SYN/ACK" : "SYN" ); if ( !(opt & PUNCH_OPT_ACK) && ctx->sin_peer_lan.sin_addr.s_addr != ctx->sin_peer_wan.sin_addr.s_addr ) { /* LAN punching... */ ret = sendto(ctx->fd, buf, len, 0, (struct sockaddr*)&ctx->sin_peer_lan, sizeof(struct sockaddr_in)); } /* WAN punching... */ if(!inner_ctx->punch_prepared) { /* the first SYN has low TTL, * this low-TTL SYN is used to punch holes on the NATs of the PC's/IPC's own side. * * next we will send normal(whose TTL has not been set) SYNs, * and these normal SYNs will be sent every 1 second. * why 1 second, see the function udp_punch. */ int original_ttl, new_ttl, ttl_len; new_ttl = PUNCH_PREPARING_TTL; ttl_len = sizeof(original_ttl); if(getsockopt(ctx->fd, IPPROTO_IP, IP_TTL, (char *) &original_ttl, &ttl_len) || setsockopt(ctx->fd, IPPROTO_IP, IP_TTL, (char *) &new_ttl, sizeof(new_ttl)) ) { inner_ctx->punch_prepared = 1; return 0; } /* send multiple times, avoid packet loss */ for(i = 0; i < 3; ++i) { sendto(ctx->fd, buf, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)); } setsockopt(ctx->fd, IPPROTO_IP, IP_TTL, (char *) &original_ttl, ttl_len); inner_ctx->punch_prepared = 1; return 0; } ret = sendto(ctx->fd, buf, len, 0, (struct sockaddr*)&sin, sizeof(struct sockaddr_in)); if ( ret < 0 ) { if ( !sock_func_will_block(ret) ) { DBG_LOG(DBG_ERR, "sendto failed, fd:%d, sock_errno:%d\n", ctx->fd, sock_errno); goto FAILED; } return 0; } inner_ctx->punch_try_cnt ++; if(!(opt & PUNCH_OPT_ACK) && inner_ctx->punch_try_cnt > 3) { /* if we have sent the low-TTL SYN, as well as 3 normal SYNs(this takes 4 seconds approximately), * but hole punching still not done, we start to do port prediction. * * NOTE: port prediction strategy will be changed if we have better one. */ sin2 = sin; for(i = 1; i < 5; i++) { sin2.sin_port = htons(ntohs(sin.sin_port) + i); sendto(ctx->fd, buf, len, 0, (struct sockaddr *)&sin2, sizeof(struct sockaddr_in)); } } return 0; FAILED: return -1; } static void punch_event_cb(evutil_socket_t fd, short events, void* arg) { punch_ctx_t* ctx = arg; punch_inner_data_t* inner_ctx = ctx->inner_data; int opt_ack = 0; if (events & EV_TIMEOUT) { opt_ack = (PUNCH_SYN_SENT != inner_ctx->status) ? PUNCH_OPT_ACK : 0; stun_send_syn(ctx, opt_ack); return ; } if (events & EV_READ) { char buf[512] = {0}; struct sockaddr_in sin; socklen_t socklen = sizeof(sin); int size; size = recvfrom(fd, buf, sizeof(buf)-1, 0, (struct sockaddr*)&sin, &socklen); if ( size < 0 ) { /* for udp socket, WSAENETRESET means TTL expired. * this is an ICMP error, called asynchronous error, * and only winSocket will tell udp socket this error, * others like bsd/linux will not. */ DBG_LOG(DBG_ERR, "recvfrom failed, fd:%d, sock_errno:%d\n", fd, sock_errno); if ( !sock_func_will_block(size) ) { goto FAILED; } return; } /* SYN received */ int syn_recv = !strcmp(buf, ctx->stun_sid); if (syn_recv) { if ( PRIVATE_NIPV4(sin.sin_addr.s_addr) || /* LAN */ PUNCH_SYN_SENT == inner_ctx->status ) { /* ����ΪLAN�� */ inner_ctx->sin_peer = sin; inner_ctx->status = PUNCH_SYN_RCVD; } stun_send_syn(ctx, PUNCH_OPT_ACK); DBG_LOG(DBG_DBG, "recvd SYN from %s\n", _sockaddr_ntoa(&sin)); return; } else { buf[0]--; int ack_recv = !strcmp(buf, ctx->stun_sid); if (ack_recv) { DBG_LOG(DBG_DBG, "recvd SYN, ACK from %s\n", _sockaddr_ntoa(&sin)); } else { DBG_LOG(DBG_DBG, "recvd trash data(%d bytes) from %s\n", size, _sockaddr_ntoa(&sin)); return; } } if ( PUNCH_SYN_SENT == inner_ctx->status ) { /* û���յ��Է���SYN����ֱ���յ�SYN+ACK */ /* ����Գ���+IP���� */ inner_ctx->sin_peer = sin; stun_send_syn(ctx, PUNCH_OPT_ACK); } else if (PUNCH_SYN_RCVD == inner_ctx->status) { /* prefer local to remote/harpin connections */ int is_local_connection = PRIVATE_NIPV4(inner_ctx->sin_peer.sin_addr.s_addr); int synack_from_remote_ip = sin.sin_addr.s_addr != inner_ctx->sin_peer.sin_addr.s_addr; if (is_local_connection && synack_from_remote_ip) { return; } /* received SYN, SYN/ACK from different remote address */ int different_addr = (inner_ctx->sin_peer.sin_addr.s_addr != sin.sin_addr.s_addr) || (inner_ctx->sin_peer.sin_port != sin.sin_port); if (different_addr) { inner_ctx->sin_peer = sin; } } else { DBG_LOG(DBG_ERR, "punching status error: %d\n", inner_ctx->status); return; } /* punching succeed */ DBG_LOG(DBG_DBG, "UDP hole punching succeed, peer address: %s\n", _sockaddr_ntoa(&inner_ctx->sin_peer)); stun_send_syn(ctx, PUNCH_OPT_ACK); inner_ctx->status = PUNCH_SYNACK_RCVD; int ret = udt_async_connect(ctx, 1, 0); if ( ret < 0 ) { goto FAILED; } return; } return; FAILED: DBG_LOG(DBG_ERR, "punching failed\n"); ctx->error_cb(ctx->env); } int udp_punch_send_stream(punch_ctx_t* ctx, const void* data, int size) { punch_inner_data_t* inner_ctx; int sent = 0; if (!ctx || !ctx->inner_data || !data || size < 0) { return -1; } inner_ctx = ctx->inner_data; if ( !(inner_ctx->status & PUNCH_UDT_CONNECTED) ) { return 0; } if ( !size ) { return (int)evbuffer_get_length(inner_ctx->evbuf_out); } /* data enqueue in evbuffer, and sent when timer expires */ if ( evbuffer_add(inner_ctx->evbuf_out, (char*)data+sent, size-sent) < 0 ) { return -1; } return (int)evbuffer_get_length(inner_ctx->evbuf_out); } int udp_punch(punch_ctx_t* ctx) { punch_inner_data_t* inner_ctx; struct timeval tv = {1,1}; if (!ctx || !ctx->inner_data ) { return -1; } inner_ctx = ctx->inner_data; inner_ctx->evstun = event_new(ctx->base, ctx->fd, EV_READ|EV_TIMEOUT|EV_PERSIST, punch_event_cb, ctx); if (!inner_ctx->evstun) { DBG_LOG(DBG_ERR, "create evstun event, error\n"); return -1; } event_add(inner_ctx->evstun, &tv); int opt_ack = 0; stun_send_syn(ctx, opt_ack); stun_send_syn(ctx, opt_ack); inner_ctx->status = PUNCH_SYN_SENT; return 0; } int udp_punch_clear_internal(punch_ctx_t* ctx) { punch_inner_data_t* inner_ctx; if ( !ctx || !ctx->inner_data ) { return -1; } inner_ctx = ctx->inner_data; if ( inner_ctx->evstun ) { event_free(inner_ctx->evstun); } if ( inner_ctx->fd_udt != -1 ) { /* since UDP fd has been binded to UDT fd, we must avoid double closeing UDP fd */ udt_close(inner_ctx->fd_udt); } else if (ctx->fd != -1) { evutil_closesocket(ctx->fd); } if ( inner_ctx->evbuf_out ) { evbuffer_free(inner_ctx->evbuf_out); } free(ctx->inner_data); ctx->inner_data = NULL; return 0; } int udp_punch_init_internal(punch_ctx_t* ctx) { punch_inner_data_t* inner_ctx; if (!ctx || !ctx->base || ctx->fd < 0 ) { return -1; } udp_punch_clear_internal(ctx); ctx->inner_data = calloc(1, sizeof(punch_inner_data_t)); if (!ctx->inner_data) { return -1; } inner_ctx = ctx->inner_data; inner_ctx->fd_udt = -1; inner_ctx->udt_sndlowat = UDT_SNDLOWAT; inner_ctx->evstun = NULL; inner_ctx->evbuf_out = evbuffer_new(); if ( !inner_ctx->evbuf_out ) { DBG_LOG(DBG_ERR, "create evbuf_out, error\n"); udp_punch_clear_internal(ctx); return -1; } return 0; } int udp_punch_set_attr(punch_ctx_t* ctx, int attr, void* value) { punch_inner_data_t* inner_ctx; if( !ctx || !ctx->inner_data || !value ) { return -1; } inner_ctx = ctx->inner_data; switch(attr) { case PUNCHING_ATTR_UDT_SNDLOWAT: { unsigned int udt_sndlowat; udt_sndlowat = *(unsigned int*)value; if( udt_sndlowat <= 0 ) { return -1; } DBG_LOG(DBG_DBG, "udt_sndlowat changed: %u -> %u\n", inner_ctx->udt_sndlowat, udt_sndlowat); inner_ctx->udt_sndlowat = udt_sndlowat; return 0; }/* case of PUNCHING_ATTR_UDT_SNDLOWAT */ default: return -1; } return -1; }
最新发布
11-15
#include <ntifs.h> #include <ntddk.h> #include <intrin.h> #include "ptehook.h" #define CR0_WP (1 << 16) #define _WIN32_WINNT 0x0601 #define NTOS_MODE_USER void HexDump(const void* data, size_t size); typedef INT(*LDE_DISASM)(PVOID address, INT bits); typedef unsigned long DWORD; typedef unsigned __int64 ULONG64; // 使用WDK标准类型 typedef unsigned char BYTE; typedef LONG NTSTATUS; // 修正的跳板指令结构 #pragma pack(push, 1) typedef struct _JMP_ABS { BYTE opcode[6]; // FF 25 00 00 00 00 = jmp [rip+0] ULONG64 address; // 目标地址 (紧跟在指令后) } JMP_ABS, * PJMP_ABS; #pragma pack(pop) static_assert(sizeof(JMP_ABS) == 14, "JMP_ABS size must be 14 bytes"); LDE_DISASM lde_disasm; // 初始化引擎 VOID lde_init() { lde_disasm = (LDE_DISASM)ExAllocatePool(NonPagedPool, 12800); memcpy(lde_disasm, szShellCode, 12800); } // 得到完整指令长度,避免截断 ULONG GetFullPatchSize(PUCHAR Address) { ULONG LenCount = 0, Len = 0; // 至少需要14字节 while (LenCount <= 14) { Len = lde_disasm(Address, 64); Address = Address + Len; LenCount = LenCount + Len; } return LenCount; } #define PROCESS_NAME_LENGTH 16 #define DRIVER_TAG 'HKOB' EXTERN_C char* PsGetProcessImageFileName(PEPROCESS process); char target_process_name[] = "oxygen.exe"; typedef NTSTATUS(*fn_ObReferenceObjectByHandleWithTag)( HANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, ULONG Tag, PVOID* Object, POBJECT_HANDLE_INFORMATION HandleInformation ); fn_ObReferenceObjectByHandleWithTag g_OriginalObReferenceObjectByHandleWithTag = NULL; // PTE Hook Framework #define MAX_G_BIT_RECORDS 128 #define MAX_HOOK_COUNT 64 #define PAGE_ALIGN(va) ((PVOID)((ULONG_PTR)(va) & ~0xFFF)) #define PDPTE_PS_BIT (1 << 7) #define PDE_PS_BIT (1 << 7) #define PTE_NX_BIT (1ULL << 63) #define CACHE_WB (6ULL << 3) // 页表结构定义 typedef struct _PAGE_TABLE { UINT64 LineAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 pat : 1; UINT64 global : 1; UINT64 ignored_1 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_2 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PteAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 large_page : 1; UINT64 global : 1; UINT64 ignored_2 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PdeAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 ignored_1 : 1; UINT64 page_size : 1; UINT64 ignored_2 : 4; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PdpteAddress; UINT64* Pml4Address; BOOLEAN IsLargePage; BOOLEAN Is1GBPage; UINT64 OriginalPte; UINT64 OriginalPde; UINT64 OriginalPdpte; UINT64 OriginalPml4e; HANDLE ProcessId; } PAGE_TABLE, * PPAGE_TABLE; // G位信息记录结构体 typedef struct _G_BIT_INFO { void* AlignAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 large_page : 1; UINT64 global : 1; UINT64 ignored_2 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PdeAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 pat : 1; UINT64 global : 1; UINT64 ignored_1 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_2 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PteAddress; BOOLEAN IsLargePage; } G_BIT_INFO, * PG_BIT_INFO; typedef struct _HOOK_INFO { void* OriginalAddress; void* HookAddress; UINT8 OriginalBytes[20]; UINT8 HookBytes[20]; UINT32 HookLength; BOOLEAN IsHooked; HANDLE ProcessId; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 pat : 1; UINT64 global : 1; UINT64 ignored_1 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_2 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*HookedPte; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 large_page : 1; UINT64 global : 1; UINT64 ignored_2 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*HookedPde; } HOOK_INFO; class PteHookManager { public: bool fn_pte_inline_hook_bp_pg(HANDLE process_id, _Inout_ void** ori_addr, void* hk_addr); bool fn_remove_hook(HANDLE process_id, void* hook_addr); static PteHookManager* GetInstance(); HOOK_INFO* GetHookInfo() { return m_HookInfo; } char* GetTrampLinePool() { return m_TrampLinePool; } UINT32 GetHookCount() { return m_HookCount; } bool fn_resume_global_bits(void* align_addr); ~PteHookManager(); // 添加析构函数声明 private: bool WriteTrampolineInstruction(void* trampoline, const JMP_ABS& jmpCmd); void fn_add_g_bit_info(void* align_addr, void* pde_address, void* pte_address); bool fn_isolation_pagetable(UINT64 cr3_val, void* replace_align_addr, void* split_pde); bool fn_isolation_pages(HANDLE process_id, void* ori_addr); bool fn_split_large_pages(void* in_pde, void* out_pde); NTSTATUS get_page_table(UINT64 cr3, PAGE_TABLE& table); void* fn_pa_to_va(UINT64 pa); UINT64 fn_va_to_pa(void* va); __forceinline KIRQL DisableWriteProtection(); __forceinline void EnableWriteProtection(KIRQL oldIrql); void logger(const char* info, bool is_err, LONG err_code = 0); void PrintPageTableInfo(const PAGE_TABLE& table); void PrintHookInfo(const HOOK_INFO& hookInfo); void PrintGBitInfo(const G_BIT_INFO& gbitInfo); static constexpr SIZE_T MAX_HOOKS = 256; // 根据需求调整 G_BIT_INFO m_GbitRecords[MAX_G_BIT_RECORDS]; UINT32 m_GbitCount = 0; void* m_PteBase = 0; HOOK_INFO m_HookInfo[MAX_HOOK_COUNT] = { 0 }; DWORD m_HookCount = 0; char* m_TrampLinePool = nullptr; // 合并为一个声明 UINT32 m_PoolUsed = 0; static PteHookManager* m_Instance; }; PteHookManager* PteHookManager::m_Instance = nullptr; // 实现部分 __forceinline KIRQL PteHookManager::DisableWriteProtection() { KIRQL oldIrql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); __writecr0(cr0 & ~0x10000); // 清除CR0.WP位 _mm_mfence(); return oldIrql; } __forceinline void PteHookManager::EnableWriteProtection(KIRQL oldIrql) { _mm_mfence(); UINT64 cr0 = __readcr0(); __writecr0(cr0 | 0x10000); // 设置CR0.WP位 KeLowerIrql(oldIrql); } void PteHookManager::logger(const char* info, bool is_err, LONG err_code) { if (is_err) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] ERROR: %s (0x%X)\n", info, err_code); } else { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] INFO: %s\n", info); } } void PteHookManager::PrintPageTableInfo(const PAGE_TABLE& table) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] Page Table Info for VA: 0x%p\n", (void*)table.LineAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PML4E: 0x%llx (Address: 0x%p)\n", table.OriginalPml4e, table.Pml4Address); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PDPTE: 0x%llx (Address: 0x%p), Is1GBPage: %d\n", table.OriginalPdpte, table.PdpteAddress, table.Is1GBPage); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PDE: 0x%llx (Address: 0x%p), IsLargePage: %d\n", table.OriginalPde, table.PdeAddress, table.IsLargePage); if (!table.IsLargePage && !table.Is1GBPage) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PTE: 0x%llx (Address: 0x%p)\n", table.OriginalPte, table.PteAddress); } } void PteHookManager::PrintHookInfo(const HOOK_INFO& hookInfo) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] Hook Info:\n"); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Original Address: 0x%p\n", hookInfo.OriginalAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Hook Address: 0x%p\n", hookInfo.HookAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Hook Length: %d\n", hookInfo.HookLength); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Is Hooked: %d\n", hookInfo.IsHooked); // 打印原始字节 DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Original Bytes: "); for (UINT32 i = 0; i < sizeof(hookInfo.OriginalBytes); i++) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "%02X ", hookInfo.OriginalBytes[i]); } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "\n"); // 打印Hook字节 DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Hook Bytes: "); for (UINT32 i = 0; i < sizeof(hookInfo.HookBytes); i++) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "%02X ", hookInfo.HookBytes[i]); } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "\n"); } void PteHookManager::PrintGBitInfo(const G_BIT_INFO& gbitInfo) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] G-Bit Info:\n"); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " Align Address: 0x%p\n", gbitInfo.AlignAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " IsLargePage: %d\n", gbitInfo.IsLargePage); if (gbitInfo.PdeAddress) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PDE: 0x%llx (Address: 0x%p)\n", gbitInfo.PdeAddress->value, gbitInfo.PdeAddress); } if (gbitInfo.PteAddress) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, " PTE: 0x%llx (Address: 0x%p)\n", gbitInfo.PteAddress->value, gbitInfo.PteAddress); } } void* PteHookManager::fn_pa_to_va(UINT64 pa) { PHYSICAL_ADDRESS physAddr; physAddr.QuadPart = pa; return MmGetVirtualForPhysical(physAddr); } UINT64 PteHookManager::fn_va_to_pa(void* va) { PHYSICAL_ADDRESS physAddr = MmGetPhysicalAddress(va); return physAddr.QuadPart; } NTSTATUS PteHookManager::get_page_table(UINT64 cr3_val, PAGE_TABLE& table) { UINT64 va = table.LineAddress; UINT64 pml4e_index = (va >> 39) & 0x1FF; UINT64 pdpte_index = (va >> 30) & 0x1FF; UINT64 pde_index = (va >> 21) & 0x1FF; UINT64 pte_index = (va >> 12) & 0x1FF; // PML4 UINT64 pml4_pa = cr3_val & ~0xFFF; UINT64* pml4_va = (UINT64*)fn_pa_to_va(pml4_pa); if (!pml4_va) return STATUS_INVALID_ADDRESS; table.Pml4Address = &pml4_va[pml4e_index]; table.OriginalPml4e = *table.Pml4Address; if (!(table.OriginalPml4e & 1)) return STATUS_ACCESS_VIOLATION; // PDPTE UINT64 pdpte_pa = table.OriginalPml4e & ~0xFFF; UINT64* pdpte_va = (UINT64*)fn_pa_to_va(pdpte_pa); if (!pdpte_va) return STATUS_INVALID_ADDRESS; table.PdpteAddress = (decltype(table.PdpteAddress))&pdpte_va[pdpte_index]; table.OriginalPdpte = table.PdpteAddress->value; table.Is1GBPage = (table.PdpteAddress->flags.page_size) ? TRUE : FALSE; if (!(table.OriginalPdpte & 1)) return STATUS_ACCESS_VIOLATION; if (table.Is1GBPage) return STATUS_SUCCESS; // PDE UINT64 pde_pa = table.OriginalPdpte & ~0xFFF; UINT64* pde_va = (UINT64*)fn_pa_to_va(pde_pa); if (!pde_va) return STATUS_INVALID_ADDRESS; table.PdeAddress = (decltype(table.PdeAddress))&pde_va[pde_index]; table.OriginalPde = table.PdeAddress->value; table.IsLargePage = (table.PdeAddress->flags.large_page) ? TRUE : FALSE; if (!(table.OriginalPde & 1)) return STATUS_ACCESS_VIOLATION; if (table.IsLargePage) return STATUS_SUCCESS; // PTE UINT64 pte_pa = table.OriginalPde & ~0xFFF; UINT64* pte_va = (UINT64*)fn_pa_to_va(pte_pa); if (!pte_va) return STATUS_INVALID_ADDRESS; table.PteAddress = (decltype(table.PteAddress))&pte_va[pte_index]; table.OriginalPte = table.PteAddress->value; if (!(table.OriginalPte & 1)) return STATUS_ACCESS_VIOLATION; // 打印页表信息 PrintPageTableInfo(table); return STATUS_SUCCESS; } bool PteHookManager::fn_split_large_pages(void* in_pde_ptr, void* out_pde_ptr) { auto in_pde = (decltype(PAGE_TABLE::PdeAddress))in_pde_ptr; auto out_pde = (decltype(PAGE_TABLE::PdeAddress))out_pde_ptr; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 正在拆分大页: 输入PDE=0x%llx, 输出PDE=0x%p\n", in_pde->value, out_pde); PHYSICAL_ADDRESS LowAddr = { 0 }, HighAddr = { 0 }; HighAddr.QuadPart = MAXULONG64; auto pt = (decltype(PAGE_TABLE::PteAddress))MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); if (!pt) { logger("分配连续内存失败 (用于拆分大页)", true); return false; } UINT64 start_pfn = in_pde->flags.page_frame_number; for (int i = 0; i < 512; i++) { pt[i].value = 0; pt[i].flags.present = 1; pt[i].flags.write = in_pde->flags.write; pt[i].flags.user = in_pde->flags.user; pt[i].flags.write_through = in_pde->flags.write_through; pt[i].flags.cache_disable = in_pde->flags.cache_disable; pt[i].flags.accessed = in_pde->flags.accessed; pt[i].flags.dirty = in_pde->flags.dirty; pt[i].flags.global = 0; pt[i].flags.page_frame_number = start_pfn + i; } out_pde->value = in_pde->value; out_pde->flags.large_page = 0; out_pde->flags.page_frame_number = fn_va_to_pa(pt) >> 12; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 大页拆分完成: 新PTE表物理地址=0x%llx\n", fn_va_to_pa(pt)); return true; } bool PteHookManager::fn_isolation_pagetable(UINT64 cr3_val, void* replace_align_addr, void* split_pde_ptr) { PHYSICAL_ADDRESS LowAddr = { 0 }, HighAddr = { 0 }; HighAddr.QuadPart = MAXULONG64; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 开始隔离页表: CR3=0x%llx, 地址=0x%p\n", cr3_val, replace_align_addr); auto Va4kb = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); auto VaPt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); auto VaPdt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); auto VaPdpt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); if (!VaPt || !Va4kb || !VaPdt || !VaPdpt) { if (VaPt) MmFreeContiguousMemory(VaPt); if (Va4kb) MmFreeContiguousMemory(Va4kb); if (VaPdt) MmFreeContiguousMemory(VaPdt); if (VaPdpt) MmFreeContiguousMemory(VaPdpt); logger("分配连续内存失败 (用于隔离页表)", true); return false; } PAGE_TABLE Table = { 0 }; Table.LineAddress = (UINT64)replace_align_addr; NTSTATUS status = get_page_table(cr3_val, Table); if (!NT_SUCCESS(status)) { MmFreeContiguousMemory(VaPt); MmFreeContiguousMemory(Va4kb); MmFreeContiguousMemory(VaPdt); MmFreeContiguousMemory(VaPdpt); logger("获取页表信息失败", true, status); return false; } UINT64 pte_index = (Table.LineAddress >> 12) & 0x1FF; UINT64 pde_index = (Table.LineAddress >> 21) & 0x1FF; UINT64 pdpte_index = (Table.LineAddress >> 30) & 0x1FF; UINT64 pml4e_index = (Table.LineAddress >> 39) & 0x1FF; memcpy(Va4kb, replace_align_addr, PAGE_SIZE); if (Table.IsLargePage && split_pde_ptr) { auto split_pde = (decltype(PAGE_TABLE::PdeAddress))split_pde_ptr; memcpy(VaPt, (void*)(split_pde->flags.page_frame_number << 12), PAGE_SIZE); } else { memcpy(VaPt, (void*)(Table.PdeAddress->flags.page_frame_number << 12), PAGE_SIZE); } memcpy(VaPdt, (void*)(Table.PdpteAddress->flags.page_frame_number << 12), PAGE_SIZE); memcpy(VaPdpt, (void*)(Table.Pml4Address[pml4e_index] & ~0xFFF), PAGE_SIZE); auto new_pte = (decltype(PAGE_TABLE::PteAddress))VaPt; new_pte[pte_index].flags.page_frame_number = fn_va_to_pa(Va4kb) >> 12; auto new_pde = (decltype(PAGE_TABLE::PdeAddress))VaPdt; new_pde[pde_index].value = Table.OriginalPde; new_pde[pde_index].flags.large_page = 0; new_pde[pde_index].flags.page_frame_number = fn_va_to_pa(VaPt) >> 12; auto new_pdpte = (decltype(PAGE_TABLE::PdpteAddress))VaPdpt; new_pdpte[pdpte_index].flags.page_frame_number = fn_va_to_pa(VaPdt) >> 12; auto new_pml4 = (UINT64*)fn_pa_to_va(cr3_val & ~0xFFF); new_pml4[pml4e_index] = (new_pml4[pml4e_index] & 0xFFF) | (fn_va_to_pa(VaPdpt) & ~0xFFF); __invlpg(replace_align_addr); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 页表隔离完成: 新PFN=0x%llx\n", fn_va_to_pa(Va4kb) >> 12); return true; } bool PteHookManager::fn_isolation_pages(HANDLE process_id, void* ori_addr) { PEPROCESS Process; if (!NT_SUCCESS(PsLookupProcessByProcessId(process_id, &Process))) { logger("查找进程失败", true); return false; } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 开始隔离页面: PID=%d, 地址=0x%p\n", (ULONG)(ULONG_PTR)process_id, ori_addr); KAPC_STATE ApcState; KeStackAttachProcess(Process, &ApcState); void* AlignAddr = PAGE_ALIGN(ori_addr); PAGE_TABLE Table = { 0 }; Table.LineAddress = (UINT64)AlignAddr; UINT64 target_cr3 = *(UINT64*)((UCHAR*)Process + 0x28); if (!NT_SUCCESS(get_page_table(target_cr3, Table))) { KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); logger("获取目标进程页表失败", true); return false; } bool success = false; decltype(PAGE_TABLE::PdeAddress) split_pde = nullptr; if (Table.IsLargePage) { split_pde = (decltype(PAGE_TABLE::PdeAddress))ExAllocatePoolWithTag(NonPagedPool, sizeof(*split_pde), 'pdeS'); if (!split_pde || !fn_split_large_pages(Table.PdeAddress, split_pde)) { if (split_pde) ExFreePoolWithTag(split_pde, 'pdeS'); KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); logger("拆分大页失败", true); return false; } if (Table.PdeAddress->flags.global) { Table.PdeAddress->flags.global = 0; fn_add_g_bit_info(AlignAddr, Table.PdeAddress, nullptr); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 清除大页G位: PDE=0x%llx\n", Table.PdeAddress->value); } } else if (Table.PteAddress && Table.PteAddress->flags.global) { Table.PteAddress->flags.global = 0; fn_add_g_bit_info(AlignAddr, nullptr, Table.PteAddress); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 清除PTE G位: PTE=0x%llx\n", Table.PteAddress->value); success = fn_isolation_pagetable(__readcr3(), AlignAddr, split_pde); if (split_pde) ExFreePoolWithTag(split_pde, 'pdeS'); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 页表状态: IsLargePage=%d, Is1GBPage=%d\n", Table.IsLargePage, Table.Is1GBPage); if (Table.PteAddress) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] PTE 值: 0x%llx (G位=%d)\n", Table.PteAddress->value, Table.PteAddress->flags.global); } KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); if (success) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 页面隔离成功\n"); } else { logger("页面隔离失败", true); } return success; } KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); return true; } bool PteHookManager::WriteTrampolineInstruction(void* trampoline, const JMP_ABS& jmpCmd) { // 1. 确保8字节对齐 if (reinterpret_cast<ULONG_PTR>(trampoline) & 0x7) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 错误: 跳板地址未对齐 (0x%p)\n", trampoline); return false; } // 2. 禁用写保护 KIRQL oldIrql = DisableWriteProtection(); // 3. 直接写入内存 RtlCopyMemory(trampoline, &jmpCmd, sizeof(JMP_ABS)); // 4. 刷新缓存 __invlpg(trampoline); _mm_mfence(); // 5. 恢复写保护 EnableWriteProtection(oldIrql); // 6. 验证写入 BYTE buffer[sizeof(JMP_ABS)]; RtlCopyMemory(buffer, trampoline, sizeof(buffer)); if (memcmp(buffer, &jmpCmd, sizeof(jmpCmd)) != 0) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 验证失败! 内存内容:\n"); HexDump(buffer, sizeof(buffer)); return false; } // 7. 反汇编验证 DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 跳板指令: jmp [rip+0] -> 0x%016llX\n", jmpCmd.address); return true; } // 辅助函数:十六进制转储 void HexDump(const void* data, size_t size) { const BYTE* bytes = static_cast<const BYTE*>(data); for (size_t i = 0; i < size; ++i) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "%02X ", bytes[i]); if ((i + 1) % 16 == 0) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "\n"); } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "\n"); } bool PteHookManager::fn_pte_inline_hook_bp_pg(HANDLE process_id, _Inout_ void** ori_addr, void* hk_addr) { if (!ori_addr || !hk_addr || !*ori_addr) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 错误: 无效参数 (ori_addr=%p, hk_addr=%p)\n", ori_addr, hk_addr); return false; } // 分配跳板池(如果尚未分配) if (!m_TrampLinePool) { PHYSICAL_ADDRESS LowAddr = { LowAddr.QuadPart = 0x100000 }; PHYSICAL_ADDRESS HighAddr = { HighAddr.QuadPart = ~0ull }; m_TrampLinePool = (char*)MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE * 8, LowAddr, HighAddr, LowAddr, MmNonCached); if (!m_TrampLinePool) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 错误: 无法分配跳板池内存\n"); return false; } // 设置内存保护属性 PMDL pMdl = IoAllocateMdl(m_TrampLinePool, PAGE_SIZE * 8, FALSE, FALSE, NULL); if (pMdl) { MmBuildMdlForNonPagedPool(pMdl); MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE); IoFreeMdl(pMdl); } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 跳板池分配成功: 地址=0x%p, 大小=%d字节\n", m_TrampLinePool, PAGE_SIZE * 8); } // 计算跳板位置(8字节对齐) void* trampoline = (void*)((ULONG_PTR)(m_TrampLinePool + m_PoolUsed + 7) & ~7) ; SIZE_T requiredSize = ((char*)trampoline - m_TrampLinePool) + sizeof(JMP_ABS); // 构造正确的跳转指令 JMP_ABS jmpCmd = {}; memcpy(jmpCmd.opcode, "\xFF\x25\x00\x00\x00\x00", 6); // jmp [rip+0] jmpCmd.address = reinterpret_cast<ULONG64>(hk_addr); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 构造跳转指令:\n" " 目标地址: 0x%p\n" " 跳板位置: 0x%p\n" " 指令格式: FF 25 00 00 00 00 + 8字节地址\n", hk_addr, trampoline); // 写入跳板指令 if (!WriteTrampolineInstruction(trampoline, jmpCmd)) { return false; } // 记录Hook信息 bool hookRecorded = false; for (UINT32 i = 0; i < MAX_HOOK_COUNT; i++) { if (!m_HookInfo[i].IsHooked) { m_HookInfo[i].OriginalAddress = *ori_addr; m_HookInfo[i].HookAddress = trampoline; m_HookInfo[i].ProcessId = process_id; m_HookInfo[i].IsHooked = TRUE; RtlCopyMemory(m_HookInfo[i].HookBytes, &jmpCmd, sizeof(jmpCmd)); m_HookInfo[i].HookLength = sizeof(JMP_ABS); m_HookCount++; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] Hook记录 #%d: 原始地址=0x%p, 跳板=0x%p\n", i, *ori_addr, trampoline); hookRecorded = true; break; } } if (!hookRecorded) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 错误: 超过最大Hook数量限制 (%d)\n", MAX_HOOK_COUNT); return false; } // 更新原始地址为跳板地址 *ori_addr = trampoline; m_PoolUsed = (UINT32)requiredSize; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] Hook安装成功! 跳板指令:\n" " jmp [rip+0] -> 0x%p\n", hk_addr); return true; } // 析构函数清理资源 PteHookManager::~PteHookManager() { if (m_TrampLinePool) { MmFreeContiguousMemory(m_TrampLinePool); m_TrampLinePool = nullptr; } } bool PteHookManager::fn_remove_hook(HANDLE process_id, void* hook_addr) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 尝试移除Hook: Hook地址=0x%p\n", hook_addr); for (UINT32 i = 0; i < m_HookCount; i++) { if (m_HookInfo[i].HookAddress == hook_addr && m_HookInfo[i].IsHooked) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 找到匹配的Hook: 原始地址=0x%p\n", m_HookInfo[i].OriginalAddress); KIRQL oldIrql = DisableWriteProtection(); memcpy(m_HookInfo[i].OriginalAddress, m_HookInfo[i].OriginalBytes, sizeof(m_HookInfo[i].OriginalBytes)); EnableWriteProtection(oldIrql); m_HookInfo[i].IsHooked = FALSE; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] Hook已成功移除\n"); return true; } } logger("未找到匹配的Hook", true); return false; } void PteHookManager::fn_add_g_bit_info(void* align_addr, void* pde_address, void* pte_address) { if (m_GbitCount >= MAX_G_BIT_RECORDS) { logger("达到最大G位记录数量限制", true); return; } PG_BIT_INFO record = &m_GbitRecords[m_GbitCount++]; record->AlignAddress = align_addr; record->PdeAddress = (decltype(G_BIT_INFO::PdeAddress))pde_address; record->PteAddress = (decltype(G_BIT_INFO::PteAddress))pte_address; record->IsLargePage = (pde_address && ((decltype(PAGE_TABLE::PdeAddress))pde_address)->flags.large_page); // 打印G位信息 PrintGBitInfo(*record); } bool PteHookManager::fn_resume_global_bits(void* align_addr) { KIRQL oldIrql = DisableWriteProtection(); bool found = false; DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, "[PTE_HOOK] 开始恢复G位: 对齐地址=0x%p\n", align_addr); for (UINT32 i = 0; i < m_GbitCount; i++) { PG_BIT_INFO record = &m_GbitRecords[i]; if (align_addr && record->AlignAddress != align_addr) continue; if (record->PteAddress) { record->PteAddress->flags.global = 1; __invlpg(record->AlignAddress); DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, " 恢复PTE G位: PTE=0x%llx, 地址=0x%p\n", record->PteAddress->value, record->AlignAddress); } if (record->PdeAddress) { record->PdeAddress->flags.global = 1; if (record->IsLargePage) { __invlpg(record->AlignAddress); } DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, " 恢复PDE G位: PDE=0x%llx, 地址=0x%p, 大页=%d\n", record->PdeAddress->value, record->AlignAddress, record->IsLargePage); } found = true; if (align_addr) break; } EnableWriteProtection(oldIrql); if (found) { DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, "[PTE_HOOK] G位恢复完成\n"); } else { logger("未找到匹配的G位记录", true); } return found; } PteHookManager* PteHookManager::GetInstance() { if (!m_Instance) { m_Instance = static_cast<PteHookManager*>( ExAllocatePoolWithTag(NonPagedPool, sizeof(PteHookManager), 'tpHk')); if (m_Instance) { RtlZeroMemory(m_Instance, sizeof(PteHookManager)); DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_INFO_LEVEL, "[PTE_HOOK] PTE Hook管理器实例已创建: 地址=0x%p\n", m_Instance); } else { DbgPrintEx(DPFLTR_ERROR_LEVEL, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] 创建PTE Hook管理器实例失败\n"); } } return m_Instance; } // 全局PTE Hook管理器实例 PteHookManager* g_PteHookManager = nullptr; // 辅助函数:检查是否为目标进程 BOOLEAN IsTargetProcess(CHAR* imageName) { CHAR currentName[16]; // 复制到本地缓冲区并确保 NULL 终止 RtlCopyMemory(currentName, imageName, 16); currentName[15] = '\0'; // 确保终止 // 修剪尾部空格 for (int i = 15; i >= 0; i--) { if (currentName[i] == ' ') currentName[i] = '\0'; else if (currentName[i] != '\0') break; } return (strcmp(currentName, target_process_name) == 0); } // Hook 函数 NTSTATUS MyObReferenceObjectByHandleWithTag( HANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, ULONG Tag, PVOID* Object, POBJECT_HANDLE_INFORMATION HandleInformation ) { __debugbreak(); // 强制中断,确认是否执行到这里 PEPROCESS currentProcess = PsGetCurrentProcess(); CHAR* imageName = PsGetProcessImageFileName(currentProcess); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[!] [HookFunction] 进入 Hook 函数! 当前进程: %s\n", imageName); if (IsTargetProcess(imageName)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[!] [HookFunction] 拒绝访问目标进程 PID=%d\n", HandleToULong(PsGetCurrentProcessId())); return STATUS_ACCESS_DENIED; } return g_OriginalObReferenceObjectByHandleWithTag( Handle, DesiredAccess, ObjectType, AccessMode, Tag, Object, HandleInformation ); } NTSTATUS InstallHook() { UNICODE_STRING funcName; RtlInitUnicodeString(&funcName, L"ObReferenceObjectByHandleWithTag"); g_OriginalObReferenceObjectByHandleWithTag = (fn_ObReferenceObjectByHandleWithTag)MmGetSystemRoutineAddress(&funcName); if (!g_OriginalObReferenceObjectByHandleWithTag) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [InstallHook] 找到 ObReferenceObjectByHandleWithTag\n"); return STATUS_NOT_FOUND; } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [InstallHook] 找到目标函数地址: %p\n", g_OriginalObReferenceObjectByHandleWithTag); void* targetFunc = (void*)g_OriginalObReferenceObjectByHandleWithTag; void* hookFunc = (void*)MyObReferenceObjectByHandleWithTag; HANDLE currentProcessId = PsGetCurrentProcessId(); if (!g_PteHookManager->fn_pte_inline_hook_bp_pg(currentProcessId, &targetFunc, hookFunc)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [InstallHook] PTE Hook 安装失败\n"); return STATUS_UNSUCCESSFUL; } g_OriginalObReferenceObjectByHandleWithTag = (fn_ObReferenceObjectByHandleWithTag)targetFunc; DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [InstallHook] Hook 成功安装. 跳板地址: %p\n", targetFunc); return STATUS_SUCCESS; } // 移除 Hook VOID RemoveHook() { if (g_OriginalObReferenceObjectByHandleWithTag && g_PteHookManager) { g_PteHookManager->fn_remove_hook(PsGetCurrentProcessId(), (void*)MyObReferenceObjectByHandleWithTag); } } // 工作线程函数 VOID InstallHookWorker(PVOID Context) { UNREFERENCED_PARAMETER(Context); DbgPrint("[+] Worker thread started for hook installation\n"); InstallHook(); PsTerminateSystemThread(STATUS_SUCCESS); } // 进程创建回调 VOID ProcessNotifyCallback( _In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOOLEAN Create ) { UNREFERENCED_PARAMETER(ParentId); if (Create) { PEPROCESS process = NULL; if (NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &process))) { CHAR* imageName = PsGetProcessImageFileName(process); CHAR currentName[16]; RtlCopyMemory(currentName, imageName, 16); currentName[15] = '\0'; for (int i = 15; i >= 0; i--) { if (currentName[i] == ' ') currentName[i] = '\0'; else if (currentName[i] != '\0') break; } if (strcmp(currentName, target_process_name) == 0) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [ProcessNotifyCallback] 目标进程 %s 创建 (PID: %d)\n", currentName, HandleToULong(ProcessId)); HANDLE threadHandle; NTSTATUS status = PsCreateSystemThread( &threadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, InstallHookWorker, NULL ); if (NT_SUCCESS(status)) { ZwClose(threadHandle); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [ProcessNotifyCallback] 工作线程已创建\n"); } else { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [ProcessNotifyCallback] 创建线程失败: 0x%X\n", status); } } ObDereferenceObject(process); } } } // 驱动卸载函数 VOID DriverUnload(PDRIVER_OBJECT DriverObject) { UNREFERENCED_PARAMETER(DriverObject); DbgPrint("[+] Driver unloading...\n"); // 移除进程通知回调 PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)ProcessNotifyCallback, TRUE); // 移除Hook RemoveHook(); // 清理PTE Hook资源 if (g_PteHookManager) { DbgPrint("[PTE_HOOK] Cleaning up PTE...\n"); // 恢复所有被修改的G位 g_PteHookManager->fn_resume_global_bits(nullptr); // 移除所有活动的Hook HOOK_INFO* hookInfo = g_PteHookManager->GetHookInfo(); UINT32 hookCount = g_PteHookManager->GetHookCount(); for (UINT32 i = 0; i < hookCount; i++) { if (hookInfo[i].IsHooked) { g_PteHookManager->fn_remove_hook(PsGetCurrentProcessId(), hookInfo[i].HookAddress); } } // 释放跳板池内存 char* trampLinePool = g_PteHookManager->GetTrampLinePool(); if (trampLinePool) { ExFreePoolWithTag(trampLinePool, 'JmpP'); } // 释放管理器实例 ExFreePoolWithTag(g_PteHookManager, 'tpHk'); g_PteHookManager = nullptr; } DbgPrint("[+] Driver unloaded successfully\n"); } extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(RegistryPath); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [DriverEntry] 驱动加载开始\n"); DriverObject->DriverUnload = DriverUnload; g_PteHookManager = PteHookManager::GetInstance(); if (!g_PteHookManager) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [DriverEntry] 初始化 PteHookManager 失败\n"); return STATUS_INSUFFICIENT_RESOURCES; } NTSTATUS status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)ProcessNotifyCallback, FALSE); if (!NT_SUCCESS(status)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] [DriverEntry] 注册进程通知失败 (0x%X)\n", status); return status; } DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[+] [DriverEntry] 驱动加载成功\n"); return STATUS_SUCCESS; } 将整个代码修改正确
06-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值