mirror of
https://github.com/Pharaoh2k/ps5debug-NG.git
synced 2026-10-22 03:42:51 -05:00
Rescanning with a "between (A to B)" comparison crashed the console (SceShellCore SIGSEGV -> kernel panic): proc_scan_count_handle passed prevValue = NULL, but the async "between" comparator reads its upper bound from prevValue. Long-standing since v1.2.2; only the async rescan + between combo triggers it. - scan.c: for "between", point prev at the upper bound in the scan-value buffer (pattern + value_length), as proc_scan_start_handle already does. - scan_compare.c: harden both comparators - cmpType 4-10 return false instead of dereferencing a NULL prev/extra operand. - Strip stray comments re-introduced this session (proc.c/scan.c/scan_compare.c) to match the public-release convention. Bump version 1.2.6 to 1.2.7.
675 lines
22 KiB
C
675 lines
22 KiB
C
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "protocol.h"
|
|
#include "sdk_shim.h"
|
|
#include "net.h"
|
|
#include "proc.h"
|
|
#include "kern_rw_fast.h"
|
|
#include <ps5/kernel.h>
|
|
|
|
static int vmmap_offs_initialized = 0;
|
|
static uint64_t vmmap_nentries_adj = 0;
|
|
static uint64_t vmmap_name_adj = 0;
|
|
|
|
static void vmmap_init_offsets(void) {
|
|
uint32_t fw = kernel_get_fw_version();
|
|
|
|
int write_adj = ((fw & 0xffff0000u) >= 0x6000000u) ? 1 : 0;
|
|
|
|
if (write_adj) {
|
|
vmmap_nentries_adj = 8;
|
|
vmmap_name_adj = 0xE;
|
|
}
|
|
vmmap_offs_initialized = 1;
|
|
}
|
|
|
|
int sys_proc_vm_map(uint32_t pid, void **out_maps, int *out_count) {
|
|
if (out_maps) *out_maps = NULL;
|
|
if (out_count) *out_count = 0;
|
|
|
|
if ((int32_t)pid <= 0) return 1;
|
|
|
|
if (!vmmap_offs_initialized) vmmap_init_offsets();
|
|
|
|
intptr_t kproc = kernel_get_proc_fast((pid_t)pid);
|
|
if (!kproc) return 1;
|
|
|
|
intptr_t vmspace_kaddr = 0;
|
|
if (kernel_copyout_fast(kproc + 0x200, &vmspace_kaddr, sizeof(vmspace_kaddr)) != 0) return 1;
|
|
|
|
uint8_t vmspace_buf[0x350];
|
|
memset(vmspace_buf, 0, sizeof(vmspace_buf));
|
|
if (kernel_copyout_fast(vmspace_kaddr, vmspace_buf, sizeof(vmspace_buf)) != 0) return 1;
|
|
|
|
int32_t n_entries = *(int32_t *)(vmspace_buf + 0x1A8 + (uintptr_t)vmmap_nentries_adj);
|
|
if (n_entries <= 0) return 1;
|
|
|
|
void *out_buf = malloc((size_t)n_entries * sizeof(struct proc_vm_map_entry));
|
|
if (!out_buf) return 1;
|
|
|
|
intptr_t cur_entry = *(intptr_t *)(vmspace_buf + 8);
|
|
uint8_t *out_p = (uint8_t *)out_buf;
|
|
uint8_t *out_end = out_p + (size_t)n_entries * sizeof(struct proc_vm_map_entry);
|
|
|
|
while (cur_entry != 0) {
|
|
uint8_t entry_buf[0x1C0];
|
|
memset(entry_buf, 0, sizeof(entry_buf));
|
|
if (kernel_copyout_fast(cur_entry, entry_buf, sizeof(entry_buf)) != 0) {
|
|
free(out_buf);
|
|
return 1;
|
|
}
|
|
|
|
*(uint64_t *)(out_p + 0x20) = *(uint64_t *)(entry_buf + 0x20);
|
|
*(uint64_t *)(out_p + 0x28) = *(uint64_t *)(entry_buf + 0x28);
|
|
*(uint64_t *)(out_p + 0x30) = *(uint64_t *)(entry_buf + 0x58);
|
|
|
|
uint8_t prot_byte = entry_buf[0x64] & 0x0F;
|
|
if (prot_byte == 4) prot_byte = 5;
|
|
*(uint16_t *)(out_p + 0x38) = (uint16_t)prot_byte;
|
|
|
|
memcpy(out_p, entry_buf + 0x142 + (uintptr_t)vmmap_name_adj, 0x20);
|
|
|
|
cur_entry = *(intptr_t *)(entry_buf + 8);
|
|
out_p += sizeof(struct proc_vm_map_entry);
|
|
if (out_p >= out_end) break;
|
|
}
|
|
|
|
if (out_maps) *out_maps = out_buf;
|
|
if (out_count) *out_count = n_entries;
|
|
return 0;
|
|
}
|
|
|
|
int proc_scan_handle(int fd, struct cmd_packet *packet) {
|
|
struct cmd_proc_scan_packet *sp = (struct cmd_proc_scan_packet *)packet->data;
|
|
if (!sp) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
uint64_t value_length = proc_scan_getSizeOfValueType(sp->valueType);
|
|
if (value_length == 0) value_length = sp->lenData;
|
|
|
|
uint8_t *data = (uint8_t *)net_alloc_buffer(sp->lenData);
|
|
if (!data) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
net_recv_all(fd, data, sp->lenData, 1);
|
|
|
|
void *maps = NULL;
|
|
int count = 0;
|
|
if (sys_proc_vm_map(sp->pid, &maps, &count) != 0) {
|
|
net_send_int32(fd, CMD_ERROR);
|
|
free(data);
|
|
return 1;
|
|
}
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
|
|
const uint8_t *extra = (sp->lenData == value_length) ? NULL : &data[value_length];
|
|
uint8_t *scan_buf = (uint8_t *)net_alloc_buffer(0x4000);
|
|
|
|
if (count > 0 && scan_buf) {
|
|
struct proc_vm_map_entry *entry = (struct proc_vm_map_entry *)maps;
|
|
for (int i = 0; i < count; i++,
|
|
entry = (struct proc_vm_map_entry *)
|
|
((uint8_t *)entry + sizeof(*entry))) {
|
|
if (!(entry->prot & 1)) continue;
|
|
|
|
uint64_t start = entry->start;
|
|
uint64_t section_len = entry->end - start;
|
|
if (!section_len) continue;
|
|
|
|
for (uint64_t j = 0; j < section_len; j += value_length) {
|
|
uint64_t off = j & 0x3FFF;
|
|
if (j == 0 || off == 0) {
|
|
|
|
proc_read_mem(sp->pid, start, 0x4000, scan_buf);
|
|
off = j & 0x3FFF;
|
|
}
|
|
uint64_t cur_addr = start + j;
|
|
if (proc_scan_legacy_compareValues(sp->compareType, sp->valueType,
|
|
value_length, data,
|
|
&scan_buf[off], extra)) {
|
|
net_send_all(fd, &cur_addr, 8);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint64_t endflag = 0xFFFFFFFFFFFFFFFFull;
|
|
net_send_all(fd, &endflag, 8);
|
|
|
|
if (scan_buf) free(scan_buf);
|
|
if (maps) free(maps);
|
|
free(data);
|
|
return 0;
|
|
}
|
|
|
|
int proc_scan_aob_handle(int fd, struct cmd_packet *packet) {
|
|
struct cmd_proc_scan_aob_packet *sp = (struct cmd_proc_scan_aob_packet *)packet->data;
|
|
if (!sp || sp->pattern_length == 0) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
uint32_t plen = sp->pattern_length;
|
|
|
|
uint64_t step_unit = proc_scan_getSizeOfValueType(10);
|
|
if (step_unit == 0) step_unit = plen;
|
|
|
|
uint8_t *pattern = (uint8_t *)net_alloc_buffer(plen);
|
|
if (!pattern) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
uint8_t *mask = (uint8_t *)net_alloc_buffer((uint32_t)step_unit);
|
|
if (!mask) {
|
|
free(pattern);
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
net_recv_all(fd, pattern, plen, 1);
|
|
net_recv_all(fd, mask, (int)step_unit, 1);
|
|
|
|
uint64_t chunk_size = 0x100000;
|
|
if (chunk_size % step_unit != 0) chunk_size = (chunk_size / step_unit) * step_unit;
|
|
|
|
uint8_t *read_buf = (uint8_t *)net_alloc_buffer(chunk_size);
|
|
if (!read_buf) {
|
|
free(pattern);
|
|
free(mask);
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
|
|
uint64_t address = sp->address;
|
|
uint64_t remaining = sp->length;
|
|
uint64_t match_count = 0;
|
|
uint64_t match_addr = 0;
|
|
uint8_t stop_flag = sp->stop_flag;
|
|
uint8_t max_matches = sp->max_matches;
|
|
int stop_unique = (stop_flag == 1);
|
|
int invalidated = 0;
|
|
int found_done = 0;
|
|
|
|
while (remaining > 0) {
|
|
uint64_t to_read = (chunk_size < remaining) ? chunk_size : remaining;
|
|
memset(read_buf, 0, to_read);
|
|
proc_read_mem(sp->pid, address, to_read, read_buf);
|
|
|
|
uint64_t limit = (to_read >= plen) ? to_read - plen : 0;
|
|
for (uint64_t j = 0; j <= limit; j++) {
|
|
if (aob_match(plen, pattern, &read_buf[j], 0, mask)) {
|
|
match_count++;
|
|
if (match_count == max_matches) {
|
|
match_addr = address + j;
|
|
if (!stop_unique) { found_done = 1; break; }
|
|
} else if (match_count > max_matches && stop_unique) {
|
|
match_addr = 0;
|
|
invalidated = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (found_done || invalidated) break;
|
|
if (chunk_size >= remaining) break;
|
|
|
|
uint64_t advance = chunk_size - plen + 1;
|
|
address += advance;
|
|
remaining = (remaining > advance) ? remaining - advance : 0;
|
|
}
|
|
|
|
net_send_all(fd, &match_addr, 8);
|
|
free(read_buf);
|
|
free(pattern);
|
|
free(mask);
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
return 0;
|
|
}
|
|
|
|
int proc_scan_aob_multi_handle(int fd, struct cmd_packet *packet) {
|
|
struct cmd_proc_scan_aob_multi_packet *mp =
|
|
(struct cmd_proc_scan_aob_multi_packet *)packet->data;
|
|
if (!mp || mp->patterns_length == 0) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
uint32_t patterns_length = mp->patterns_length;
|
|
uint8_t *blob = (uint8_t *)net_alloc_buffer(patterns_length);
|
|
if (!blob) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
net_recv_all(fd, blob, patterns_length, 1);
|
|
|
|
uint16_t pat_count = 0;
|
|
uint64_t max_plen = 1;
|
|
{
|
|
uint32_t cursor = 0;
|
|
while (cursor + 5 <= patterns_length) {
|
|
uint32_t plen;
|
|
memcpy(&plen, blob + cursor + 1, 4);
|
|
cursor += 5 + 2 * plen;
|
|
if (plen > max_plen) max_plen = plen;
|
|
pat_count++;
|
|
}
|
|
}
|
|
uint32_t output_size = (uint32_t)pat_count * 8u;
|
|
|
|
uint8_t *read_buf = (uint8_t *)net_alloc_buffer(0x100000);
|
|
void *output = read_buf ? net_alloc_buffer(output_size) : NULL;
|
|
uint64_t *match_counts = output ? (uint64_t *)net_alloc_buffer((uint32_t)pat_count * 8u) : NULL;
|
|
if (!read_buf || !output || !match_counts) {
|
|
if (read_buf) free(read_buf);
|
|
if (output) free(output);
|
|
if (match_counts) free(match_counts);
|
|
free(blob);
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
memset(output, 0, output_size);
|
|
memset(match_counts, 0, (size_t)pat_count * 8u);
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
|
|
uint64_t address = mp->address;
|
|
uint64_t remaining = mp->length;
|
|
uint8_t stop_flag = mp->stop_flag;
|
|
int stop_unique = (stop_flag == 1);
|
|
uint16_t found_count = 0;
|
|
uint16_t invalidated_count = 0;
|
|
|
|
if (remaining > 0) {
|
|
for (;;) {
|
|
uint64_t to_read = (remaining < 0x100000) ? remaining : 0x100000;
|
|
memset(read_buf, 0, to_read);
|
|
proc_read_mem(mp->pid, address, to_read, read_buf);
|
|
|
|
uint32_t cursor = 0;
|
|
int outer_break = 0;
|
|
for (uint16_t pi = 0; pi < pat_count; pi++) {
|
|
uint8_t target_count = blob[cursor];
|
|
uint32_t plen;
|
|
memcpy(&plen, blob + cursor + 1, 4);
|
|
const uint8_t *pat = blob + cursor + 5;
|
|
const uint8_t *msk = pat + plen;
|
|
|
|
uint64_t limit = (to_read >= plen) ? to_read - plen : 0;
|
|
for (uint64_t j = 0; j <= limit; j++) {
|
|
if (aob_match(plen, pat, &read_buf[j], 0, msk)) {
|
|
match_counts[pi]++;
|
|
if (match_counts[pi] == target_count) {
|
|
uint64_t cur_addr = address + j;
|
|
memcpy((uint8_t *)output + (size_t)pi * 8u, &cur_addr, 8);
|
|
found_count++;
|
|
if (!stop_unique) break;
|
|
} else if (stop_unique &&
|
|
match_counts[pi] == (uint64_t)target_count + 1u) {
|
|
uint64_t zero = 0;
|
|
memcpy((uint8_t *)output + (size_t)pi * 8u, &zero, 8);
|
|
invalidated_count++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
cursor += 5 + 2u * plen;
|
|
|
|
if (!stop_unique && found_count >= pat_count) { outer_break = 1; break; }
|
|
if ( stop_unique && invalidated_count >= pat_count) { outer_break = 1; break; }
|
|
}
|
|
|
|
if (outer_break) break;
|
|
if (remaining <= 0x100000) break;
|
|
|
|
uint64_t advance = (uint64_t)0x100001 - max_plen;
|
|
address += advance;
|
|
remaining = (remaining > advance) ? remaining - advance : 0;
|
|
}
|
|
}
|
|
|
|
net_send_all(fd, output, (int)output_size);
|
|
free(match_counts);
|
|
free(output);
|
|
free(read_buf);
|
|
free(blob);
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
return 0;
|
|
}
|
|
|
|
int proc_scan_start_handle(int fd, struct cmd_packet *packet) {
|
|
if (!(g_proc_auth_state & 2)) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
struct cmd_proc_scan_start_packet *sp = (struct cmd_proc_scan_start_packet *)packet->data;
|
|
if (!sp) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
if (sp->compareType > 12 || sp->lenData == 0) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
int needs_scan_value = ((1u << sp->compareType) & 0x114Fu) != 0;
|
|
int is_between = (sp->compareType == 4);
|
|
int is_arrbytes = (sp->valueType == 10);
|
|
if (is_between) needs_scan_value = 1;
|
|
|
|
uint64_t value_length = proc_scan_getSizeOfValueType(sp->valueType);
|
|
if (value_length == 0) value_length = sp->lenData;
|
|
if (value_length == 0) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
uint8_t *pattern = NULL;
|
|
if (needs_scan_value && sp->lenData) {
|
|
pattern = (uint8_t *)net_alloc_buffer(sp->lenData);
|
|
if (!pattern) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
if (pattern) {
|
|
net_recv_all(fd, pattern, (int)sp->lenData, 1);
|
|
}
|
|
|
|
uint8_t *mask = NULL;
|
|
if (is_arrbytes) {
|
|
mask = (uint8_t *)net_alloc_buffer((uint32_t)value_length);
|
|
if (!mask) {
|
|
if (pattern) free(pattern);
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
net_recv_all(fd, mask, (int)value_length, 1);
|
|
}
|
|
|
|
uint64_t step = sp->alignment ? sp->alignment : value_length;
|
|
|
|
uint64_t chunk_size = 0x100000ULL;
|
|
if (chunk_size % value_length != 0) {
|
|
chunk_size = (chunk_size / value_length) * value_length;
|
|
}
|
|
|
|
uint8_t *read_buf = (uint8_t *)net_alloc_buffer(chunk_size);
|
|
uint8_t *result_buf = (uint8_t *)net_alloc_buffer(0x40000);
|
|
if (!read_buf || !result_buf) {
|
|
if (read_buf) free(read_buf);
|
|
if (result_buf) free(result_buf);
|
|
if (pattern) free(pattern);
|
|
if (mask) free(mask);
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
|
|
uint64_t addr = sp->address;
|
|
uint64_t remaining = sp->length;
|
|
uint64_t result_len = 0;
|
|
uint64_t flush_thresh = 0x3FFE8ULL - value_length;
|
|
|
|
const void *prev_for_between = is_between ? (pattern + value_length) : NULL;
|
|
|
|
while (remaining > 0) {
|
|
uint64_t to_read = (remaining > chunk_size) ? chunk_size : remaining;
|
|
memset(read_buf, 0, to_read);
|
|
proc_read_mem(sp->pid, addr, to_read, read_buf);
|
|
|
|
uint64_t limit = (to_read >= value_length) ? to_read - value_length : 0;
|
|
for (uint64_t j = 0; j <= limit; j += step) {
|
|
if (proc_scan_compareValues(sp->compareType, sp->valueType, value_length,
|
|
pattern, &read_buf[j], prev_for_between, mask)) {
|
|
if (result_len > flush_thresh) {
|
|
*(uint64_t *)result_buf = result_len;
|
|
net_send_all(fd, result_buf, (int)(result_len + 8));
|
|
result_len = 0;
|
|
}
|
|
uint32_t offset = (uint32_t)((addr + j) - sp->address);
|
|
memcpy(result_buf + 8 + result_len, &offset, 4);
|
|
memcpy(result_buf + 8 + result_len + 4, &read_buf[j], value_length);
|
|
result_len += 4 + value_length;
|
|
}
|
|
}
|
|
|
|
uint64_t advance = to_read + step - value_length;
|
|
if (advance == 0 || advance > to_read) advance = to_read;
|
|
addr += advance;
|
|
remaining = (remaining > advance) ? remaining - advance : 0;
|
|
}
|
|
|
|
if (result_len) {
|
|
*(uint64_t *)result_buf = result_len;
|
|
net_send_all(fd, result_buf, (int)(result_len + 8));
|
|
}
|
|
|
|
uint64_t sentinel = 0xFFFFFFFFFFFFFFFFULL;
|
|
net_send_all(fd, &sentinel, 8);
|
|
|
|
free(read_buf);
|
|
free(result_buf);
|
|
if (pattern) free(pattern);
|
|
if (mask) free(mask);
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
return 0;
|
|
}
|
|
|
|
int proc_scan_count_handle(int fd, struct cmd_packet *packet) {
|
|
if (!(g_proc_auth_state & 2)) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
struct cmd_proc_scan_count_packet *cp = (struct cmd_proc_scan_count_packet *)packet->data;
|
|
if (!cp) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
if (cp->compareType > 12) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
int needs_value_flag = g_cmptype_needs_value [cp->compareType] != 0;
|
|
int needs_extra_flag = g_cmptype_needs_extra [cp->compareType] != 0;
|
|
int needs_previous_flag = g_cmptype_needs_previous[cp->compareType] != 0;
|
|
int needs_scan_value = needs_value_flag || needs_extra_flag;
|
|
int is_arrbytes = (cp->valueType == 10);
|
|
int is_between = (cp->compareType == 4);
|
|
|
|
uint64_t value_length = proc_scan_getSizeOfValueType(cp->valueType);
|
|
if (value_length == 0) value_length = cp->lenData;
|
|
if (value_length == 0 || value_length > 0x1000) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
uint8_t *pattern = NULL;
|
|
uint8_t *mask = NULL;
|
|
if (needs_scan_value && cp->lenData) {
|
|
pattern = (uint8_t *)net_alloc_buffer(cp->lenData);
|
|
if (!pattern) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
}
|
|
if (is_arrbytes) {
|
|
mask = (uint8_t *)net_alloc_buffer((uint32_t)value_length);
|
|
if (!mask) {
|
|
if (pattern) free(pattern);
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
uint8_t *chunk_buf = (uint8_t *)net_alloc_buffer(0x40000);
|
|
uint8_t *result_buf = (uint8_t *)net_alloc_buffer(0x40000);
|
|
uint8_t *mem_buf = (uint8_t *)net_alloc_buffer(0x100000);
|
|
if (!chunk_buf || !result_buf || !mem_buf) {
|
|
if (chunk_buf) free(chunk_buf);
|
|
if (result_buf) free(result_buf);
|
|
if (mem_buf) free(mem_buf);
|
|
if (pattern) free(pattern);
|
|
if (mask) free(mask);
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
if (pattern) net_recv_all(fd, pattern, (int)cp->lenData, 1);
|
|
if (mask) net_recv_all(fd, mask, (int)value_length, 1);
|
|
|
|
const uint8_t *between_hi = (is_between && pattern && cp->lenData >= 2 * value_length)
|
|
? (pattern + value_length) : NULL;
|
|
|
|
int includes_prev = needs_previous_flag;
|
|
uint64_t entry_size = includes_prev ? (4 + value_length) : 4;
|
|
uint64_t flush_thresh = 0x3FFE8ULL - 2 * value_length;
|
|
|
|
for (;;) {
|
|
uint32_t chunk_len = 0;
|
|
net_recv_all(fd, &chunk_len, 4, 1);
|
|
if (chunk_len == 0xFFFFFFFFu) break;
|
|
if (chunk_len == 0) {
|
|
uint64_t per_chunk_sentinel = 0xFFFFFFFFFFFFFFFFULL;
|
|
net_send_all(fd, &per_chunk_sentinel, 8);
|
|
continue;
|
|
}
|
|
if (chunk_len > 0x40000u) break;
|
|
|
|
net_recv_all(fd, chunk_buf, (int)chunk_len, 1);
|
|
|
|
uint64_t last_entry_addr = 0;
|
|
if (chunk_len >= entry_size) {
|
|
uint32_t last_offset;
|
|
memcpy(&last_offset, chunk_buf + chunk_len - entry_size, 4);
|
|
last_entry_addr = cp->base_address + last_offset;
|
|
}
|
|
|
|
uint64_t window_start = 0;
|
|
uint64_t window_end = 0;
|
|
uint64_t result_len = 0;
|
|
|
|
for (uint64_t off = 0; off + entry_size <= chunk_len; off += entry_size) {
|
|
uint32_t entry_offset;
|
|
memcpy(&entry_offset, chunk_buf + off, 4);
|
|
const uint8_t *prev_value_ptr = includes_prev ? (chunk_buf + off + 4) : between_hi;
|
|
uint64_t addr = cp->base_address + entry_offset;
|
|
|
|
if (addr >= window_end) {
|
|
|
|
uint64_t span = (last_entry_addr >= addr)
|
|
? (last_entry_addr + value_length) - addr
|
|
: value_length;
|
|
uint32_t read_size = (span > 0x100000ULL) ? 0x100000u : (uint32_t)span;
|
|
|
|
memset(mem_buf, 0, read_size);
|
|
proc_read_mem(cp->pid, addr, (uint64_t)read_size, mem_buf);
|
|
window_start = addr;
|
|
window_end = addr + read_size;
|
|
}
|
|
|
|
const uint8_t *mem_value_ptr = mem_buf + (addr - window_start);
|
|
|
|
if (proc_scan_compareValues(cp->compareType, cp->valueType, value_length,
|
|
pattern, mem_value_ptr, prev_value_ptr, mask)) {
|
|
if (result_len > flush_thresh) {
|
|
*(uint64_t *)result_buf = result_len;
|
|
net_send_all(fd, result_buf, (int)(result_len + 8));
|
|
result_len = 0;
|
|
}
|
|
memcpy(result_buf + 8 + result_len, &entry_offset, 4);
|
|
memcpy(result_buf + 8 + result_len + 4, mem_value_ptr, value_length);
|
|
result_len += 4 + value_length;
|
|
}
|
|
}
|
|
|
|
if (result_len) {
|
|
*(uint64_t *)result_buf = result_len;
|
|
net_send_all(fd, result_buf, (int)(result_len + 8));
|
|
}
|
|
|
|
uint64_t per_chunk_sentinel = 0xFFFFFFFFFFFFFFFFULL;
|
|
net_send_all(fd, &per_chunk_sentinel, 8);
|
|
}
|
|
|
|
free(chunk_buf);
|
|
free(result_buf);
|
|
free(mem_buf);
|
|
if (pattern) free(pattern);
|
|
if (mask) free(mask);
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
return 0;
|
|
}
|
|
|
|
int proc_scan_get_handle(int fd, struct cmd_packet *packet) {
|
|
if (!(g_proc_auth_state & 2)) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
struct cmd_proc_scan_get_packet *gp = (struct cmd_proc_scan_get_packet *)packet->data;
|
|
if (!gp) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
uint32_t entries_len = gp->count * 12u;
|
|
uint8_t *entries = (uint8_t *)net_alloc_buffer(entries_len);
|
|
if (!entries) {
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
net_send_int32(fd, CMD_SUCCESS);
|
|
net_recv_all(fd, entries, (int)entries_len, 1);
|
|
|
|
uint8_t *buf = (uint8_t *)net_alloc_buffer(0x100000);
|
|
if (!buf) {
|
|
free(entries);
|
|
net_send_int32(fd, CMD_DATA_NULL);
|
|
return 1;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < gp->count; i++) {
|
|
uint64_t addr;
|
|
uint32_t length32;
|
|
memcpy(&addr, entries + 12u * i, 8);
|
|
memcpy(&length32, entries + 12u * i + 8u, 4);
|
|
uint64_t length = length32;
|
|
while (length > 0) {
|
|
uint64_t to_read = (length > 0x100000ULL) ? 0x100000ULL : length;
|
|
memset(buf, 0, to_read);
|
|
proc_read_mem(gp->pid, addr, to_read, buf);
|
|
net_send_all(fd, buf, (int)to_read);
|
|
addr += to_read;
|
|
length -= to_read;
|
|
}
|
|
}
|
|
|
|
uint64_t sentinel = 0xFFFFFFFFFFFFFFFFULL;
|
|
net_send_all(fd, &sentinel, 8);
|
|
|
|
free(entries);
|
|
free(buf);
|
|
return 0;
|
|
}
|