FUCKKKK
This commit is contained in:
+229
-11
@@ -54,9 +54,74 @@ typedef struct {
|
||||
} pe_dll_entry;
|
||||
|
||||
static pe_dll_entry g_dll_cache[PE_DLL_CACHE_MAX];
|
||||
|
||||
/* ===== 延迟 DllMain 队列 =====
|
||||
* pe_load_image 触发递归 pe_dll_load 时,PE32+ 原生执行环境尚未就绪:
|
||||
* SSE 未启用(pe_enable_sse 在 load 之后才调用)、仍跑在 16KB 内核栈上。
|
||||
* 真实 DLL 的 CRT 初始化含 SSE 指令且栈需求大,立即调用必 #UD/溢栈。
|
||||
* 故加载阶段只登记 DllMain,由 pe_service_run 在启用 SSE 并切换到
|
||||
* 1MB PE 大栈后调 pe_dll_run_pending_dllmains() 统一执行。 */
|
||||
#define PE_DLLMAIN_PENDING_MAX 32
|
||||
typedef struct {
|
||||
u64 image_base;
|
||||
u64 entry_point;
|
||||
char name[PE_DLL_NAME_MAX];
|
||||
} pe_dllmain_pending;
|
||||
static pe_dllmain_pending g_dllmain_pending[PE_DLLMAIN_PENDING_MAX];
|
||||
static int g_dllmain_pending_count = 0;
|
||||
static int g_dllmain_defer = 0;
|
||||
|
||||
/* enable=1 开启延迟模式并清空队列(每次 pe_service_run 加载前调用);
|
||||
* enable=0 恢复立即调用(兜底路径用)。 */
|
||||
void pe_dll_defer_dllmain(int enable) {
|
||||
g_dllmain_defer = enable;
|
||||
if (enable) g_dllmain_pending_count = 0;
|
||||
}
|
||||
|
||||
/* 在大栈 + SSE 环境下执行全部已登记的 DllMain(ATTACH)。
|
||||
* 执行完毕清空队列并关闭延迟模式。 */
|
||||
void pe_dll_run_pending_dllmains(void) {
|
||||
for (int i = 0; i < g_dllmain_pending_count; i++) {
|
||||
pe_dllmain_pending *p = &g_dllmain_pending[i];
|
||||
typedef int (__attribute__((ms_abi)) *dllmain_fn)(u64, u32, u64);
|
||||
dllmain_fn dm = (dllmain_fn)p->entry_point;
|
||||
int ok = dm(p->image_base, 1 /* DLL_PROCESS_ATTACH */, 0);
|
||||
if (!ok) {
|
||||
log_warn("[PE] DllMain returned FALSE (init failed)");
|
||||
log_info(p->name);
|
||||
} else {
|
||||
log_info("[PE] DllMain ATTACH ok");
|
||||
}
|
||||
}
|
||||
g_dllmain_pending_count = 0;
|
||||
g_dllmain_defer = 0;
|
||||
}
|
||||
static pe_dll_reader_fn g_dll_reader = 0;
|
||||
int g_pe_dll_manager_ready = 0;
|
||||
|
||||
/* 转发导出递归深度上限(A->B->C 链) */
|
||||
#define PE_DLL_FWD_DEPTH_MAX 8
|
||||
|
||||
/* ---- API set 重定向 ----
|
||||
* Windows 10+ 的 api-ms-win-crt-*.dll 是 API set 虚拟 DLL,
|
||||
* 物理上不存在文件,由 loader 按 schema 重定向到 ucrtbase.dll。
|
||||
* 此处实现等价映射:api-ms-win-crt-* -> ucrtbase.dll。
|
||||
* 返回目标 DLL 名(静态字符串),或 NULL 表示非 API set。 */
|
||||
static const char *apiset_redirect(const char *dll_name) {
|
||||
if (!dll_name) return 0;
|
||||
/* 大小写不敏感前缀匹配 "api-ms-win-crt-" */
|
||||
static const char prefix[] = "api-ms-win-crt-";
|
||||
int i = 0;
|
||||
while (prefix[i]) {
|
||||
char c = dll_name[i];
|
||||
if (!c) return 0;
|
||||
if (c >= 'a' && c <= 'z') c = (char)(c - 32);
|
||||
if (c != prefix[i]) return 0;
|
||||
i++;
|
||||
}
|
||||
return "ucrtbase.dll";
|
||||
}
|
||||
|
||||
/* ---- 辅助函数 ---- */
|
||||
|
||||
/* ASCII 大小写不敏感字符串比较(freestanding,无 strcmp) */
|
||||
@@ -134,12 +199,37 @@ static void extract_export_dir(u64 image_base, u32 *out_rva, u32 *out_size) {
|
||||
*out_size = data_dir[IMAGE_DIRECTORY_ENTRY_EXPORT].size;
|
||||
}
|
||||
|
||||
/* 在已加载 DLL 的导出表中按名称查找函数。
|
||||
* 返回绝对地址(image_base + func_rva),0=未找到/转发导出。 */
|
||||
static u64 resolve_export_by_name(u64 image_base, u32 export_dir_rva,
|
||||
const char *func_name) {
|
||||
/* 按序号在已加载 DLL 的导出表中查找函数(转发串 "#123" 用)。
|
||||
* 返回绝对地址,0=未找到/越界。 */
|
||||
static u64 resolve_export_by_ordinal(u64 image_base, u32 export_dir_rva,
|
||||
u32 ordinal) {
|
||||
if (export_dir_rva == 0) return 0;
|
||||
const u8 *img = (const u8 *)image_base;
|
||||
const image_export_directory *exp =
|
||||
(const image_export_directory *)(img + export_dir_rva);
|
||||
if (ordinal < exp->ordinal_base) return 0;
|
||||
u32 idx = ordinal - exp->ordinal_base;
|
||||
if (idx >= exp->number_of_functions) return 0;
|
||||
const u32 *functions = (const u32 *)(img + exp->address_of_functions);
|
||||
u32 func_rva = functions[idx];
|
||||
if (func_rva == 0) return 0;
|
||||
return image_base + func_rva;
|
||||
}
|
||||
|
||||
/* 解析转发导出串("DLL.Func" 或 "DLL.#123")。
|
||||
* fwd_str 位于 image_base+func_rva 处(导出目录数据区内)。
|
||||
* depth 防止 A→B→A 循环转发。返回绝对地址,0=失败。 */
|
||||
static u64 resolve_forwarded_export(u64 image_base, u32 func_rva, int depth);
|
||||
|
||||
/* 在已加载 DLL 的导出表中按名称查找函数。
|
||||
* 返回绝对地址(image_base + func_rva),0=未找到。
|
||||
* 转发导出自动跟随解析(PE 规范:func_rva 落在导出目录数据区内即为转发串)。 */
|
||||
static u64 resolve_export_by_name(u64 image_base, u32 export_dir_rva,
|
||||
u32 export_dir_size, const char *func_name,
|
||||
int depth) {
|
||||
if (export_dir_rva == 0) return 0;
|
||||
if (depth > PE_DLL_FWD_DEPTH_MAX) return 0;
|
||||
const u8 *img = (const u8 *)image_base;
|
||||
const image_export_directory *exp =
|
||||
(const image_export_directory *)(img + export_dir_rva);
|
||||
if (exp->number_of_names == 0) return 0;
|
||||
@@ -155,12 +245,12 @@ static u64 resolve_export_by_name(u64 image_base, u32 export_dir_rva,
|
||||
if (eat_index >= exp->number_of_functions) return 0;
|
||||
u32 func_rva = functions[eat_index];
|
||||
|
||||
/* 转发导出:func_rva 落在导出表范围内 → 是转发字符串而非代码地址 */
|
||||
/* 转发导出(PE 规范):func_rva 落在导出目录数据区
|
||||
* [export_dir_rva, export_dir_rva+export_dir_size) 内 →
|
||||
* 该处是 "DLL.Func" 转发字符串而非代码地址 */
|
||||
if (func_rva >= export_dir_rva &&
|
||||
func_rva < export_dir_rva + exp->number_of_functions * 4) {
|
||||
/* 粗略范围检查(更精确应使用 export_dir_size,但此处足够) */
|
||||
log_info("[PE] forwarded export (not supported)");
|
||||
return 0;
|
||||
func_rva < export_dir_rva + export_dir_size) {
|
||||
return resolve_forwarded_export(image_base, func_rva, depth + 1);
|
||||
}
|
||||
return image_base + func_rva;
|
||||
}
|
||||
@@ -168,6 +258,74 @@ static u64 resolve_export_by_name(u64 image_base, u32 export_dir_rva,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 转发串解析:"NTDLL.RtlInitUnicodeString" 或 "KERNEL32.#123"。
|
||||
* DLL 名通常不带 .dll 后缀(如 "UCRTBASE"),需补全。 */
|
||||
static u64 resolve_forwarded_export(u64 image_base, u32 func_rva, int depth) {
|
||||
if (depth > PE_DLL_FWD_DEPTH_MAX) {
|
||||
log_warn("[PE] forwarded export chain too deep");
|
||||
return 0;
|
||||
}
|
||||
const char *fwd = (const char *)(image_base + func_rva);
|
||||
|
||||
/* 拷贝到本地缓冲并找分隔点 '.'(转发串最大 ~64 字符,防御截断) */
|
||||
char buf[96];
|
||||
u32 i = 0;
|
||||
while (i + 1 < sizeof(buf) && fwd[i] && fwd[i] != ' ') {
|
||||
buf[i] = fwd[i];
|
||||
i++;
|
||||
}
|
||||
buf[i] = 0;
|
||||
|
||||
u32 dot = 0;
|
||||
while (buf[dot] && buf[dot] != '.') dot++;
|
||||
if (buf[dot] != '.' || dot == 0 || buf[dot + 1] == 0) {
|
||||
log_warn("[PE] malformed forwarder string");
|
||||
return 0;
|
||||
}
|
||||
buf[dot] = 0;
|
||||
const char *target_func = buf + dot + 1;
|
||||
|
||||
/* 目标 DLL 名:小写化 + 补 ".dll" 后缀 */
|
||||
char tdll[PE_DLL_NAME_MAX];
|
||||
dll_name_lower(buf, tdll, sizeof(tdll));
|
||||
int tl = 0;
|
||||
while (tdll[tl]) tl++;
|
||||
if (tl + 4 < (int)sizeof(tdll)) {
|
||||
/* 已有 ".dll" 后缀则不重复添加 */
|
||||
if (!(tl >= 4 && tdll[tl-4] == '.' &&
|
||||
(tdll[tl-3] == 'd') && (tdll[tl-2] == 'l') && (tdll[tl-1] == 'l'))) {
|
||||
tdll[tl++] = '.'; tdll[tl++] = 'd';
|
||||
tdll[tl++] = 'l'; tdll[tl++] = 'l';
|
||||
tdll[tl] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 序号转发:"#123" */
|
||||
if (target_func[0] == '#') {
|
||||
u32 ord = 0;
|
||||
const char *p = target_func + 1;
|
||||
if (*p == 0) return 0;
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
ord = ord * 10 + (u32)(*p - '0');
|
||||
p++;
|
||||
}
|
||||
if (ord == 0 || ord > 0xFFFF) return 0;
|
||||
/* 需先确保目标 DLL 已加载 */
|
||||
u64 base = 0;
|
||||
if (pe_dll_load(tdll, &base) != 0) return 0;
|
||||
int idx = dll_cache_find(tdll);
|
||||
if (idx < 0) return 0;
|
||||
u64 addr = resolve_export_by_ordinal(base, g_dll_cache[idx].export_dir_rva, ord);
|
||||
if (addr == 0) {
|
||||
log_warn("[PE] ordinal forward target not found");
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* 名称转发:递归走 pe_dll_resolve(带深度计) */
|
||||
return pe_dll_resolve_ex(tdll, target_func, depth);
|
||||
}
|
||||
|
||||
/* ---- 公共接口 ---- */
|
||||
|
||||
void pe_dll_manager_init(pe_dll_reader_fn reader) {
|
||||
@@ -185,6 +343,10 @@ int pe_dll_load(const char *dll_name, u64 *out_base) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* API set 重定向:api-ms-win-crt-* -> ucrtbase.dll */
|
||||
const char *redirected = apiset_redirect(dll_name);
|
||||
if (redirected) dll_name = redirected;
|
||||
|
||||
/* 查缓存 */
|
||||
int idx = dll_cache_find(dll_name);
|
||||
if (idx >= 0) {
|
||||
@@ -254,13 +416,49 @@ int pe_dll_load(const char *dll_name, u64 *out_base) {
|
||||
log_info(dll_name);
|
||||
log_hex64("[PE] DLL base=", info.image_base);
|
||||
|
||||
/* 调用 DllMain(hinst, DLL_PROCESS_ATTACH=1, NULL)。
|
||||
* 真实 DLL(如 ucrtbase)依赖入口完成 CRT/TLS 初始化。
|
||||
* 无入口点(AddressOfEntryPoint==0 → entry==image_base)则跳过。
|
||||
* 返回 0(初始化失败)只记告警不阻断:无状态函数仍可用。
|
||||
* 延迟模式(pe_service_run 加载阶段):只登记不调用,待 SSE 启用
|
||||
* 且切换到 1MB PE 大栈后由 pe_dll_run_pending_dllmains 统一执行。 */
|
||||
if (info.entry_point != info.image_base) {
|
||||
if (g_dllmain_defer) {
|
||||
if (g_dllmain_pending_count < PE_DLLMAIN_PENDING_MAX) {
|
||||
pe_dllmain_pending *p = &g_dllmain_pending[g_dllmain_pending_count++];
|
||||
p->image_base = info.image_base;
|
||||
p->entry_point = info.entry_point;
|
||||
int i = 0;
|
||||
for (; i < PE_DLL_NAME_MAX - 1 && entry->name[i]; i++) p->name[i] = entry->name[i];
|
||||
p->name[i] = 0;
|
||||
log_info("[PE] DllMain deferred");
|
||||
} else {
|
||||
log_warn("[PE] DllMain pending queue full, skipped");
|
||||
}
|
||||
} else {
|
||||
typedef int (__attribute__((ms_abi)) *dllmain_fn)(u64, u32, u64);
|
||||
dllmain_fn dm = (dllmain_fn)info.entry_point;
|
||||
int ok = dm(info.image_base, 1 /* DLL_PROCESS_ATTACH */, 0);
|
||||
if (!ok) {
|
||||
log_warn("[PE] DllMain returned FALSE (init failed)");
|
||||
log_info(dll_name);
|
||||
} else {
|
||||
log_info("[PE] DllMain ATTACH ok");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (out_base) *out_base = info.image_base;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 pe_dll_resolve(const char *dll_name, const char *func_name) {
|
||||
u64 pe_dll_resolve_ex(const char *dll_name, const char *func_name, int depth) {
|
||||
if (!g_pe_dll_manager_ready || !dll_name || !func_name) return 0;
|
||||
|
||||
/* API set 重定向:api-ms-win-crt-* -> ucrtbase.dll */
|
||||
const char *redirected = apiset_redirect(dll_name);
|
||||
if (redirected) dll_name = redirected;
|
||||
|
||||
/* 确保 DLL 已加载 */
|
||||
int idx = dll_cache_find(dll_name);
|
||||
if (idx < 0 || g_dll_cache[idx].state != DLL_STATE_LOADED) {
|
||||
@@ -271,5 +469,25 @@ u64 pe_dll_resolve(const char *dll_name, const char *func_name) {
|
||||
}
|
||||
|
||||
pe_dll_entry *e = &g_dll_cache[idx];
|
||||
return resolve_export_by_name(e->image_base, e->export_dir_rva, func_name);
|
||||
return resolve_export_by_name(e->image_base, e->export_dir_rva,
|
||||
e->export_dir_size, func_name, depth);
|
||||
}
|
||||
|
||||
u64 pe_dll_resolve(const char *dll_name, const char *func_name) {
|
||||
return pe_dll_resolve_ex(dll_name, func_name, 0);
|
||||
}
|
||||
|
||||
u64 pe_dll_resolve_in_base(u64 image_base, const char *func_name, u32 ordinal) {
|
||||
if (!g_pe_dll_manager_ready || image_base == 0) return 0;
|
||||
for (int i = 0; i < PE_DLL_CACHE_MAX; i++) {
|
||||
pe_dll_entry *e = &g_dll_cache[i];
|
||||
if (e->state != DLL_STATE_LOADED || e->image_base != image_base) continue;
|
||||
if (ordinal != 0)
|
||||
return resolve_export_by_ordinal(e->image_base, e->export_dir_rva, ordinal);
|
||||
if (func_name)
|
||||
return resolve_export_by_name(e->image_base, e->export_dir_rva,
|
||||
e->export_dir_size, func_name, 0);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -48,4 +48,18 @@ int pe_dll_load(const char *dll_name, u64 *out_base);
|
||||
* 返回绝对地址,0=未找到。 */
|
||||
u64 pe_dll_resolve(const char *dll_name, const char *func_name);
|
||||
|
||||
/* 带转发深度的内部变体(转发导出链 A→B→C 递归用,外部勿调)。 */
|
||||
u64 pe_dll_resolve_ex(const char *dll_name, const char *func_name, int depth);
|
||||
|
||||
/* 在已加载 DLL 的模块基址上解析导出(GetProcAddress 真实 DLL 路径用)。
|
||||
* image_base 必须是 pe_dll_load 返回的基址;func_name 与 ordinal 二选一
|
||||
* (ordinal != 0 时按序号)。返回绝对地址,0=未找到。 */
|
||||
u64 pe_dll_resolve_in_base(u64 image_base, const char *func_name, u32 ordinal);
|
||||
|
||||
/* 延迟 DllMain 控制(PE32+ 加载期 SSE/大栈未就绪,DllMain 必须延迟)。
|
||||
* pe_service_run 在 pe_load_image 前调 pe_dll_defer_dllmain(1),
|
||||
* 切换到 1MB PE 大栈后调 pe_dll_run_pending_dllmains() 统一执行。 */
|
||||
void pe_dll_defer_dllmain(int enable);
|
||||
void pe_dll_run_pending_dllmains(void);
|
||||
|
||||
#endif /* PE_DLL_MANAGER_H */
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "pe_loader.h"
|
||||
#include "pe_shim.h"
|
||||
#include "pe_dll_manager.h"
|
||||
#include "x86emu32.h"
|
||||
#include "../include/utsm/pe.h"
|
||||
#include <utsm/arena.h>
|
||||
@@ -218,19 +219,53 @@ static void resolve_imports(u8 *image, u64 image_base_actual,
|
||||
shim_idx = pe_shim_lookup(dll_name, func_name);
|
||||
}
|
||||
|
||||
/* 当 shim 未命中且需要尝试真实 DLL 时,先把 dll_name/func_name
|
||||
* 复制到本地栈缓冲。原因:pe_dll_resolve 可能触发 fat32_read_path,
|
||||
* 后者返回的 static 缓冲与外层 pe_data 可能指向同一区域,会被覆盖。 */
|
||||
char dll_buf[256];
|
||||
char func_buf[256];
|
||||
int have_local_names = 0;
|
||||
if (shim_idx < 0 && is_pe32_plus && g_pe_dll_manager_ready &&
|
||||
func_name && func_name[0] != '#') {
|
||||
u32 dl = 0;
|
||||
while (dll_name[dl] && dl + 1 < sizeof(dll_buf)) {
|
||||
dll_buf[dl] = dll_name[dl];
|
||||
dl++;
|
||||
}
|
||||
dll_buf[dl] = 0;
|
||||
u32 fl = 0;
|
||||
while (func_name[fl] && fl + 1 < sizeof(func_buf)) {
|
||||
func_buf[fl] = func_name[fl];
|
||||
fl++;
|
||||
}
|
||||
func_buf[fl] = 0;
|
||||
have_local_names = 1;
|
||||
}
|
||||
|
||||
/* 填充 IAT(image 缓冲区内) */
|
||||
u8 *iat_ptr = image + iat_rva + (u32)fn_idx * (is_pe32_plus ? 8 : 4);
|
||||
int resolved_by_real_dll = 0;
|
||||
if (is_pe32_plus) {
|
||||
u64 fn_addr;
|
||||
if (shim_idx >= 0) {
|
||||
const pe_shim_entry *se = pe_shim_get(shim_idx);
|
||||
fn_addr = (u64)se->fn64;
|
||||
} else if (have_local_names) {
|
||||
/* PE32+ 尝试真实 DLL */
|
||||
u64 real = pe_dll_resolve(dll_buf, func_buf);
|
||||
if (real != 0) {
|
||||
fn_addr = real;
|
||||
resolved_by_real_dll = 1;
|
||||
} else {
|
||||
/* DLL 加载过但函数未找到:填 unimpl stub */
|
||||
fn_addr = pe_shim_unimpl_stub();
|
||||
}
|
||||
} else {
|
||||
fn_addr = pe_shim_unimpl_stub();
|
||||
}
|
||||
*(u64 *)iat_ptr = fn_addr;
|
||||
} else {
|
||||
/* 32位:填合成地址,解释器拦截 */
|
||||
/* 32位:填合成地址,解释器拦截(不调真实 DLL) */
|
||||
u32 synth_addr;
|
||||
if (shim_idx >= 0) {
|
||||
synth_addr = PE_SHIM_ADDR_BASE | (u32)(shim_idx & 0xFFFF);
|
||||
@@ -248,11 +283,26 @@ static void resolve_imports(u8 *image, u64 image_base_actual,
|
||||
}
|
||||
}
|
||||
|
||||
if (shim_idx < 0 && func_name) {
|
||||
/* shim 未命中且真实 DLL 也未解析:记未实现日志;
|
||||
* 真实 DLL 解析成功则记来源日志(区分 shim/真实 DLL 路径)。
|
||||
* 用本地副本(pe_data 可能已被 DLL 加载破坏) */
|
||||
if (shim_idx < 0 && func_name && !resolved_by_real_dll) {
|
||||
log_info("[PE] unimplemented import");
|
||||
serial_write(dll_name);
|
||||
if (have_local_names) {
|
||||
serial_write(dll_buf);
|
||||
serial_write("!");
|
||||
serial_write(func_buf);
|
||||
} else {
|
||||
serial_write(dll_name);
|
||||
serial_write("!");
|
||||
serial_write(func_name);
|
||||
}
|
||||
serial_write("\n");
|
||||
} else if (resolved_by_real_dll) {
|
||||
log_info("[PE] import via real DLL");
|
||||
serial_write(dll_buf);
|
||||
serial_write("!");
|
||||
serial_write(func_name);
|
||||
serial_write(func_buf);
|
||||
serial_write("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
pe/pe_loader.o: pe\pe_loader.c pe\pe_loader.h include\utsm\types.h \
|
||||
include\utsm\pe.h pe\pe_shim.h pe\x86emu32.h pe\..\include\utsm\pe.h \
|
||||
include\utsm\arena.h include\utsm\log.h
|
||||
include\utsm\pe.h pe\pe_shim.h pe\pe_dll_manager.h pe\x86emu32.h \
|
||||
pe\..\include\utsm\pe.h include\utsm\arena.h include\utsm\log.h
|
||||
pe\pe_loader.h:
|
||||
include\utsm\types.h:
|
||||
include\utsm\pe.h:
|
||||
pe\pe_shim.h:
|
||||
pe\pe_dll_manager.h:
|
||||
pe\x86emu32.h:
|
||||
pe\..\include\utsm\pe.h:
|
||||
include\utsm\arena.h:
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "pe_loader.h"
|
||||
#include "pe_shim.h"
|
||||
#include "pe_dll_manager.h"
|
||||
#include "x86emu32.h"
|
||||
#include "../include/utsm/pe.h"
|
||||
#include <utsm/arena.h>
|
||||
@@ -34,13 +35,20 @@
|
||||
int pe_service_load(const void *pe_data, u64 size, pe_image_info *out);
|
||||
int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit_code);
|
||||
void pe_service_unload(pe_image_info *info);
|
||||
int pe_service_run_windowed(const void *pe_data, u64 size, const char *cmdline,
|
||||
u64 *exit_code, const pe_window_host *host);
|
||||
|
||||
/* 全局服务表实例 */
|
||||
/* 全局服务表实例(P5:ABI 尾部追加 run_windowed/inject_*,同镜像一致性
|
||||
* 假设见 pe.h;旧调用方按前 4 字段使用不受影响) */
|
||||
static const pe_service g_pe_service = {
|
||||
PE_SERVICE_MAGIC,
|
||||
pe_service_load,
|
||||
pe_service_run,
|
||||
pe_service_unload,
|
||||
pe_service_run_windowed,
|
||||
pe_shim_inject_scancode,
|
||||
pe_shim_inject_pointer,
|
||||
pe_shim_inject_input,
|
||||
};
|
||||
|
||||
const pe_service *pe_get_service(void) {
|
||||
@@ -248,6 +256,14 @@ static void pe_call_on_stack(pe_entry_fn fn, u64 stack_top) {
|
||||
"r8", "r9", "r10", "r11");
|
||||
}
|
||||
|
||||
/* PE32+ 大栈引导入口:先执行加载期延迟登记的真实 DLL DllMain(ATTACH),
|
||||
* 再跳 PE 入口。此时 SSE 已启用且运行在 1MB PE 大栈上。 */
|
||||
static pe_entry_fn g_pe_boot_entry;
|
||||
static void pe_boot_with_dllmains(void) {
|
||||
pe_dll_run_pending_dllmains();
|
||||
g_pe_boot_entry();
|
||||
}
|
||||
|
||||
/* ===== 运行 =====
|
||||
* 加载 + 执行 + 卸载.返回 0 成功,*exit_code 为进程退出码. */
|
||||
int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit_code) {
|
||||
@@ -268,13 +284,18 @@ int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit
|
||||
if (opt_magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
/* ===== PE32+ : Ring0 原生执行 ===== */
|
||||
pe_image_info info;
|
||||
/* SSE 必须在任何 PE/DLL 代码执行前启用:load 期会递归加载真实 DLL,
|
||||
* MSVC CRT 代码含 SSE 指令,后置启用曾在 DllMain 内触发 #UD。 */
|
||||
pe_enable_sse();
|
||||
/* DllMain 延迟到 1MB PE 大栈上执行(16KB 内核栈跑不动 CRT init) */
|
||||
pe_dll_defer_dllmain(1);
|
||||
int rc = pe_load_image(pe_data, size, &info);
|
||||
if (rc != 0) {
|
||||
pe_dll_defer_dllmain(0);
|
||||
log_error("[PE] PE32+ load failed");
|
||||
return -5;
|
||||
}
|
||||
log_info("[PE] running PE32+ natively");
|
||||
pe_enable_sse();
|
||||
|
||||
/* 恢复异常可见性:UTSM 交权 DSK 时 idt_halt_all() 将 IDT 全部
|
||||
* 替换为静默 halt stub,PE 原生执行期间的 CPU 异常(PF/GP/UD)
|
||||
@@ -297,10 +318,10 @@ int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit
|
||||
* 残片充当 R12-R15/RBP → 野指针 call → 三重故障). */
|
||||
u64 code = 0;
|
||||
if (__builtin_setjmp(pe_shim_exit_jmpbuf()) == 0) {
|
||||
pe_entry_fn entry = (pe_entry_fn)info.entry_point;
|
||||
log_hex64("[PE] entry=", (u64)entry);
|
||||
log_hex64("[PE] entry=", (u64)info.entry_point);
|
||||
log_hex64("[PE] stack_top=", stack_top);
|
||||
pe_call_on_stack(entry, stack_top);
|
||||
g_pe_boot_entry = (pe_entry_fn)info.entry_point;
|
||||
pe_call_on_stack(pe_boot_with_dllmains, stack_top);
|
||||
code = 0;
|
||||
} else {
|
||||
code = pe_shim_get_exit_code();
|
||||
@@ -365,3 +386,20 @@ int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit
|
||||
|
||||
return -8; /* 未知 PE magic */
|
||||
}
|
||||
|
||||
/* ===== P5 窗口模式运行 =====
|
||||
* 与 pe_service_run 相同的加载/执行路径,区别仅在 shim 行为:
|
||||
* 渲染目标重定向到 host->surface,PS/2 轮询关闭,消息空转回调
|
||||
* host->pump()(desktop 帧)。host==NULL/surface==NULL 时等价 run。 */
|
||||
int pe_service_run_windowed(const void *pe_data, u64 size, const char *cmdline,
|
||||
u64 *exit_code, const pe_window_host *host) {
|
||||
if (host && host->surface) {
|
||||
pe_shim_set_window_host(host);
|
||||
log_info("[PE] run_windowed: surface mode");
|
||||
} else {
|
||||
pe_shim_set_window_host(0);
|
||||
}
|
||||
int rc = pe_service_run(pe_data, size, cmdline, exit_code);
|
||||
pe_shim_set_window_host(0); /* 防止残留配置串到下一次 run */
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
pe/pe_service.o: pe\pe_service.c pe\pe_loader.h include\utsm\types.h \
|
||||
include\utsm\pe.h pe\pe_shim.h pe\x86emu32.h pe\..\include\utsm\pe.h \
|
||||
include\utsm\arena.h include\utsm\idt.h include\utsm\log.h
|
||||
include\utsm\pe.h pe\pe_shim.h pe\pe_dll_manager.h pe\x86emu32.h \
|
||||
pe\..\include\utsm\pe.h include\utsm\arena.h include\utsm\idt.h \
|
||||
include\utsm\log.h
|
||||
pe\pe_loader.h:
|
||||
include\utsm\types.h:
|
||||
include\utsm\pe.h:
|
||||
pe\pe_shim.h:
|
||||
pe\pe_dll_manager.h:
|
||||
pe\x86emu32.h:
|
||||
pe\..\include\utsm\pe.h:
|
||||
include\utsm\arena.h:
|
||||
|
||||
+264
-38
@@ -25,6 +25,8 @@
|
||||
*/
|
||||
|
||||
#include "pe_shim.h"
|
||||
#include "pe_dll_manager.h"
|
||||
#include "../include/utsm/pe.h" /* P5: pe_window_host */
|
||||
#include <utsm/arena.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
@@ -69,11 +71,57 @@ static inline u64 gp(u64 va) {
|
||||
return va;
|
||||
}
|
||||
|
||||
/* ===== P5 窗口模式状态 =====
|
||||
* 全屏模式(默认):s_wsurf==NULL,shim 直写 Limine fb + 轮询 PS/2。
|
||||
* 窗口模式:渲染目标为 host surface(伪造 fb),输入靠 inject_*,
|
||||
* 消息空转时回调 host pump(desktop 帧)。 */
|
||||
static u8 *s_wsurf = 0;
|
||||
static u32 s_wsurf_w = 0, s_wsurf_h = 0, s_wsurf_pitch = 0;
|
||||
static int (*s_host_pump)(void *ud) = 0;
|
||||
static void *s_host_ud = 0;
|
||||
static struct limine_framebuffer s_wsurf_fb; /* 伪造 fb(窗口模式) */
|
||||
static const pe_window_host *s_winhost_pending = 0; /* service 层挂起配置 */
|
||||
|
||||
void pe_shim_set_window_host(const pe_window_host *host) {
|
||||
s_winhost_pending = host;
|
||||
}
|
||||
|
||||
int pe_shim_window_mode(void) { return s_wsurf != 0; }
|
||||
|
||||
void pe_shim_init(const char *cmdline) {
|
||||
g_cmdline = cmdline ? cmdline : "";
|
||||
g_exit_jmp_set = 0;
|
||||
g_exit_code = 0;
|
||||
g_emu_mem_base = 0; /* BUG-007: 默认非解释器上下文(原生路径恒等映射) */
|
||||
|
||||
/* P5:应用 service 层挂起的窗口模式配置(在状态重置之后生效) */
|
||||
if (s_winhost_pending && s_winhost_pending->surface
|
||||
&& s_winhost_pending->width && s_winhost_pending->height
|
||||
&& s_winhost_pending->pitch) {
|
||||
s_wsurf = s_winhost_pending->surface;
|
||||
s_wsurf_w = s_winhost_pending->width;
|
||||
s_wsurf_h = s_winhost_pending->height;
|
||||
s_wsurf_pitch = s_winhost_pending->pitch;
|
||||
s_host_pump = s_winhost_pending->pump;
|
||||
s_host_ud = s_winhost_pending->ud;
|
||||
/* 伪造 fb:32bpp 0xAARRGGBB(与 BitBlt/SetDIBits fast path 掩码一致) */
|
||||
s_wsurf_fb.address = s_wsurf;
|
||||
s_wsurf_fb.width = s_wsurf_w;
|
||||
s_wsurf_fb.height = s_wsurf_h;
|
||||
s_wsurf_fb.pitch = s_wsurf_pitch;
|
||||
s_wsurf_fb.bpp = 32;
|
||||
s_wsurf_fb.memory_model = 1;
|
||||
s_wsurf_fb.red_mask_shift = 16; s_wsurf_fb.red_mask_size = 8;
|
||||
s_wsurf_fb.green_mask_shift = 8; s_wsurf_fb.green_mask_size = 8;
|
||||
s_wsurf_fb.blue_mask_shift = 0; s_wsurf_fb.blue_mask_size = 8;
|
||||
log_info("[shim] window mode: surface target");
|
||||
} else {
|
||||
s_wsurf = 0;
|
||||
s_wsurf_w = s_wsurf_h = s_wsurf_pitch = 0;
|
||||
s_host_pump = 0;
|
||||
s_host_ud = 0;
|
||||
}
|
||||
s_winhost_pending = 0;
|
||||
}
|
||||
|
||||
/* 返回 ExitProcess longjmp 目标 jmpbuf(见 pe_shim.h 的 BUG-006 说明).
|
||||
@@ -697,7 +745,7 @@ static u64 __attribute__((ms_abi)) shim_LoadLibraryA(u64 name_p) {
|
||||
name_p = gp(name_p);
|
||||
if (!name_p) return 0;
|
||||
const char *n = (const char *)name_p;
|
||||
/* 已知 DLL 返回伪句柄(大小写不敏感子串匹配) */
|
||||
/* 已知 shim DLL 返回伪句柄(大小写不敏感子串匹配) */
|
||||
static const char *known[] = { "kernel32", "ntdll", "user32", "gdi32", "msvcrt" };
|
||||
for (int k = 0; k < 5; k++) {
|
||||
const char *pat = known[k];
|
||||
@@ -709,7 +757,22 @@ static u64 __attribute__((ms_abi)) shim_LoadLibraryA(u64 name_p) {
|
||||
if (a != b) break;
|
||||
i++;
|
||||
}
|
||||
if (pat[i] == 0) return 0x10000020;
|
||||
if (pat[i] == 0) return PE_SHIM_FAKE_MODULE;
|
||||
}
|
||||
}
|
||||
/* 未知 DLL:尝试从 SYSTEM/lib 加载真实 DLL(句柄=镜像基址) */
|
||||
if (g_pe_dll_manager_ready) {
|
||||
char nb[64];
|
||||
u32 i = 0;
|
||||
while (n[i] && i + 1 < sizeof(nb)) { nb[i] = n[i]; i++; }
|
||||
nb[i] = 0;
|
||||
u64 base = 0;
|
||||
if (pe_dll_load(nb, &base) == 0 && base != 0) {
|
||||
log_info("[shim] LoadLibrary real DLL ok");
|
||||
serial_write(" -> ");
|
||||
serial_write(nb);
|
||||
serial_write("\n");
|
||||
return base;
|
||||
}
|
||||
}
|
||||
g_last_error = 126; /* ERROR_MOD_NOT_FOUND */
|
||||
@@ -723,13 +786,22 @@ static u64 __attribute__((ms_abi)) shim_lstrlenW(u64 str_p) {
|
||||
return n;
|
||||
}
|
||||
|
||||
/* GetProcAddress — 在 shim 表内按函数名全局查找(hModule 为伪句柄,不限定 DLL).
|
||||
* lpProcName 高 16 位为 0 时是 ordinal(不支持,返回 0)。
|
||||
* Rust std 用它动态探测 Rtl 系列/dbghelp API,命中返回真实 shim 地址,miss 返回 0。 */
|
||||
/* GetProcAddress — 伪句柄在 shim 表内按函数名全局查找(不限定 DLL);
|
||||
* 真实 DLL 句柄(pe_dll_load 返回的镜像基址)在该 DLL 导出表内解析。
|
||||
* lpProcName 高 16 位为 0 时是 ordinal。 */
|
||||
static u64 __attribute__((ms_abi)) shim_GetProcAddress(u64 module, u64 name_p) {
|
||||
(void)module;
|
||||
name_p = gp(name_p);
|
||||
if (!name_p) return 0;
|
||||
/* 真实 DLL 模块:按基址解析(支持名称与序号) */
|
||||
if (module && module != PE_SHIM_FAKE_MODULE && g_pe_dll_manager_ready) {
|
||||
u32 ord = ((name_p >> 16) == 0) ? (u32)(name_p & 0xFFFF) : 0;
|
||||
u64 addr = pe_dll_resolve_in_base(module,
|
||||
ord ? 0 : (const char *)name_p, ord);
|
||||
if (addr) return addr;
|
||||
g_last_error = 127; /* ERROR_PROC_NOT_FOUND */
|
||||
return 0;
|
||||
}
|
||||
(void)module;
|
||||
if ((name_p >> 16) == 0) { /* ordinal 导入 */
|
||||
g_last_error = 127; /* ERROR_PROC_NOT_FOUND */
|
||||
return 0;
|
||||
@@ -1153,8 +1225,47 @@ static void shim_mouse_byte(u8 b) {
|
||||
s_mouse_btn = nbtn;
|
||||
}
|
||||
|
||||
/* 排空 PS/2 输出缓冲,转成 Win32 消息入队 */
|
||||
/* 单个 set-1 扫描码 -> Win32 消息入队(P5 抽出:全屏 PS/2 轮询与
|
||||
* 窗口模式 host 注入共用同一份 vk 映射/修饰键跟踪/WM_CHAR 合成)。
|
||||
* sc: 原始扫描码(bit7=release);e0: 1=E0 扩展键。 */
|
||||
static void shim_kbd_inject(u8 sc, int e0) {
|
||||
if (!e0) {
|
||||
if (sc == 0x2A || sc == 0x36) { s_kbd_shift = 1; shim_msg_push(SHIM_WM_KEYDOWN, 0x10, sc); return; }
|
||||
if (sc == 0xAA || sc == 0xB6) { s_kbd_shift = 0; shim_msg_push(SHIM_WM_KEYUP, 0x10, sc); return; }
|
||||
if (sc == 0x1D) { s_kbd_ctrl = 1; shim_msg_push(SHIM_WM_KEYDOWN, 0x11, sc); return; }
|
||||
if (sc == 0x9D) { s_kbd_ctrl = 0; shim_msg_push(SHIM_WM_KEYUP, 0x11, sc); return; }
|
||||
if (sc == 0x38) { s_kbd_alt = 1; shim_msg_push(SHIM_WM_KEYDOWN, 0x12, sc); return; }
|
||||
if (sc == 0xB8) { s_kbd_alt = 0; shim_msg_push(SHIM_WM_KEYUP, 0x12, sc); return; }
|
||||
}
|
||||
if (sc & 0x80) {
|
||||
u32 vk = shim_scan_vk(sc & 0x7F, e0);
|
||||
if (vk) {
|
||||
shim_msg_push(SHIM_WM_KEYUP, vk, sc);
|
||||
if (s_dbg_key < 16) { s_dbg_key++; log_hex64("[shim] KEYUP vk=", vk); }
|
||||
}
|
||||
return;
|
||||
}
|
||||
u32 vk = shim_scan_vk(sc, e0);
|
||||
if (vk) {
|
||||
shim_msg_push(SHIM_WM_KEYDOWN, vk, sc);
|
||||
if (s_dbg_key < 16) { s_dbg_key++; log_hex64("[shim] KEYDOWN vk=", vk); }
|
||||
/* Esc -> 额外合成 WM_CLOSE:无鼠标环境下关闭窗口的唯一途径 */
|
||||
if (vk == 0x1B && !e0) shim_msg_push(SHIM_WM_CLOSE, 0, 0);
|
||||
}
|
||||
if (!e0) {
|
||||
char c = shim_scan_ascii(sc, s_kbd_shift);
|
||||
if (c >= ' ' && c < 0x7F) {
|
||||
shim_msg_push(SHIM_WM_CHAR, (u64)(u8)c, sc);
|
||||
if (s_dbg_key < 16) { s_dbg_key++; log_hex64("[shim] CHAR ch=", (u64)(u8)c); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 排空 PS/2 输出缓冲,转成 Win32 消息入队。
|
||||
* P5 窗口模式:输入权归 desktop(经 inject_* 入队),此函数 no-op,
|
||||
* 绝不触碰 PS/2 端口(避免与 desktop 的输入采集竞争)。 */
|
||||
static void shim_kbd_poll(void) {
|
||||
if (s_wsurf) return; /* 窗口模式:host 注入,不轮询端口 */
|
||||
shim_mouse_init_once();
|
||||
for (;;) {
|
||||
u8 st = inb(0x64);
|
||||
@@ -1167,37 +1278,64 @@ static void shim_kbd_poll(void) {
|
||||
}
|
||||
if (sc == 0xE0) { s_kbd_e0 = 1; continue; }
|
||||
int e0 = s_kbd_e0;
|
||||
if (!e0) {
|
||||
if (sc == 0x2A || sc == 0x36) { s_kbd_shift = 1; shim_msg_push(SHIM_WM_KEYDOWN, 0x10, sc); continue; }
|
||||
if (sc == 0xAA || sc == 0xB6) { s_kbd_shift = 0; shim_msg_push(SHIM_WM_KEYUP, 0x10, sc); continue; }
|
||||
if (sc == 0x1D) { s_kbd_ctrl = 1; shim_msg_push(SHIM_WM_KEYDOWN, 0x11, sc); continue; }
|
||||
if (sc == 0x9D) { s_kbd_ctrl = 0; shim_msg_push(SHIM_WM_KEYUP, 0x11, sc); continue; }
|
||||
if (sc == 0x38) { s_kbd_alt = 1; shim_msg_push(SHIM_WM_KEYDOWN, 0x12, sc); continue; }
|
||||
if (sc == 0xB8) { s_kbd_alt = 0; shim_msg_push(SHIM_WM_KEYUP, 0x12, sc); continue; }
|
||||
}
|
||||
s_kbd_e0 = 0;
|
||||
if (sc & 0x80) {
|
||||
u32 vk = shim_scan_vk(sc & 0x7F, e0);
|
||||
if (vk) {
|
||||
shim_msg_push(SHIM_WM_KEYUP, vk, sc);
|
||||
if (s_dbg_key < 16) { s_dbg_key++; log_hex64("[shim] KEYUP vk=", vk); }
|
||||
}
|
||||
continue;
|
||||
}
|
||||
u32 vk = shim_scan_vk(sc, e0);
|
||||
if (vk) {
|
||||
shim_msg_push(SHIM_WM_KEYDOWN, vk, sc);
|
||||
if (s_dbg_key < 16) { s_dbg_key++; log_hex64("[shim] KEYDOWN vk=", vk); }
|
||||
/* Esc -> 额外合成 WM_CLOSE:无鼠标环境下关闭窗口的唯一途径 */
|
||||
if (vk == 0x1B && !e0) shim_msg_push(SHIM_WM_CLOSE, 0, 0);
|
||||
}
|
||||
if (!e0) {
|
||||
char c = shim_scan_ascii(sc, s_kbd_shift);
|
||||
if (c >= ' ' && c < 0x7F) {
|
||||
shim_msg_push(SHIM_WM_CHAR, (u64)(u8)c, sc);
|
||||
if (s_dbg_key < 16) { s_dbg_key++; log_hex64("[shim] CHAR ch=", (u64)(u8)c); }
|
||||
}
|
||||
}
|
||||
shim_kbd_inject(sc, e0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== P5 窗口模式输入注入(pe_service 经 ABI 转发到这里)===== */
|
||||
|
||||
int pe_shim_inject_scancode(u32 scancode, u32 e0_prefix) {
|
||||
if (!s_wsurf) return -1;
|
||||
shim_kbd_inject((u8)scancode, e0_prefix ? 1 : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pe_shim_inject_pointer(i32 x, i32 y, u32 buttons) {
|
||||
if (!s_wsurf) return -1;
|
||||
/* 钳位到 surface 范围 */
|
||||
if (x < 0) x = 0; else if (x >= (i32)s_wsurf_w) x = (i32)s_wsurf_w - 1;
|
||||
if (y < 0) y = 0; else if (y >= (i32)s_wsurf_h) y = (i32)s_wsurf_h - 1;
|
||||
|
||||
u8 nbtn = (u8)(buttons & 0x07);
|
||||
i32 cx = x - g_wnd_x, cy = y - g_wnd_y; /* 客户区坐标(消息 lparam) */
|
||||
u64 lp = (u64)(u32)(((u32)(u16)cy << 16) | (u32)(u16)cx);
|
||||
u64 mk = 0;
|
||||
if (nbtn & 1) mk |= SHIM_MK_LBUTTON;
|
||||
if (nbtn & 2) mk |= SHIM_MK_RBUTTON;
|
||||
if (nbtn & 4) mk |= SHIM_MK_MBUTTON;
|
||||
if (s_kbd_shift) mk |= SHIM_MK_SHIFT;
|
||||
if (s_kbd_ctrl) mk |= SHIM_MK_CONTROL;
|
||||
|
||||
if (x != s_mouse_x || y != s_mouse_y) {
|
||||
s_mouse_x = x; s_mouse_y = y;
|
||||
shim_msg_push_pt(SHIM_WM_MOUSEMOVE, mk, lp, x, y);
|
||||
}
|
||||
/* 按钮边沿 */
|
||||
if ((nbtn & 1) && !(s_mouse_btn & 1)) shim_msg_push_pt(SHIM_WM_LBUTTONDOWN, mk, lp, x, y);
|
||||
if (!(nbtn & 1) && (s_mouse_btn & 1)) shim_msg_push_pt(SHIM_WM_LBUTTONUP, mk, lp, x, y);
|
||||
if ((nbtn & 2) && !(s_mouse_btn & 2)) shim_msg_push_pt(SHIM_WM_RBUTTONDOWN, mk, lp, x, y);
|
||||
if (!(nbtn & 2) && (s_mouse_btn & 2)) shim_msg_push_pt(SHIM_WM_RBUTTONUP, mk, lp, x, y);
|
||||
if ((nbtn & 4) && !(s_mouse_btn & 4)) shim_msg_push_pt(SHIM_WM_MBUTTONDOWN, mk, lp, x, y);
|
||||
if (!(nbtn & 4) && (s_mouse_btn & 4)) shim_msg_push_pt(SHIM_WM_MBUTTONUP, mk, lp, x, y);
|
||||
s_mouse_btn = nbtn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pe_shim_inject_input(u32 msg, u64 wparam, u64 lparam, i32 ptx, i32 pty) {
|
||||
if (!s_wsurf) return -1;
|
||||
shim_msg_push_pt(msg, wparam, lparam, ptx, pty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 消息空转让出点:窗口模式回调 host 泵(desktop 帧),全屏 pause。
|
||||
* pump 返回非 0 = host 请求退出 → 投递 WM_CLOSE(PE 自愿退出路径)。 */
|
||||
static void shim_msg_yield(void) {
|
||||
if (s_host_pump) {
|
||||
if (s_host_pump(s_host_ud))
|
||||
shim_msg_push(SHIM_WM_CLOSE, 0, 0);
|
||||
} else {
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1209,6 +1347,8 @@ static u64 __attribute__((ms_abi)) shim_RegisterClassExW(u64 wc_p) {
|
||||
}
|
||||
|
||||
static const struct limine_framebuffer *shim_fb(void) {
|
||||
/* P5 窗口模式:渲染目标是 host 提供的内存 surface(伪造 fb) */
|
||||
if (s_wsurf) return &s_wsurf_fb;
|
||||
if (!g_fb_request.response || g_fb_request.response->framebuffer_count == 0) return 0;
|
||||
return g_fb_request.response->framebuffers[0];
|
||||
}
|
||||
@@ -1315,6 +1455,9 @@ static u64 __attribute__((ms_abi)) shim_PeekMessageW(u64 msg_p, u64 hwnd,
|
||||
u64 fmin, u64 fmax, u64 remove) {
|
||||
(void)hwnd; (void)fmin; (void)fmax;
|
||||
shim_kbd_poll();
|
||||
/* P5 窗口模式:PeekMessage 驱动的渲染循环(Deaicup 型)下 PE 几乎不
|
||||
* 调 GetMessage,desktop 只能靠这里的空转让出获得 CPU 跑帧。 */
|
||||
if (g_mq_count == 0 && s_host_pump) shim_msg_yield();
|
||||
if (g_mq_count == 0) return 0;
|
||||
shim_msg_t *m = &g_msgq[g_mq_head];
|
||||
if (msg_p) *(shim_msg_t *)msg_p = *m;
|
||||
@@ -1330,7 +1473,7 @@ static u64 __attribute__((ms_abi)) shim_GetMessageW(u64 msg_p, u64 hwnd,
|
||||
for (;;) { /* 阻塞语义:轮询键盘直到有消息 */
|
||||
shim_kbd_poll();
|
||||
if (g_mq_count > 0) break;
|
||||
__asm__ volatile("pause");
|
||||
shim_msg_yield(); /* P5: 窗口模式泵 desktop,全屏 pause */
|
||||
}
|
||||
shim_msg_t *m = &g_msgq[g_mq_head];
|
||||
if (msg_p) *(shim_msg_t *)msg_p = *m;
|
||||
@@ -1434,6 +1577,7 @@ static const char *const g_cursor_bmp[12] = {
|
||||
};
|
||||
|
||||
static void shim_draw_cursor(const struct limine_framebuffer *fb) {
|
||||
if (s_wsurf) return; /* P5 窗口模式:光标由 desktop 统一绘制 */
|
||||
if (!s_mouse_ok || !g_wnd_created) return;
|
||||
i32 wx1 = g_wnd_x + g_wnd_w, wy1 = g_wnd_y + g_wnd_h;
|
||||
if (s_mouse_x < g_wnd_x || s_mouse_y < g_wnd_y) return;
|
||||
@@ -1528,6 +1672,87 @@ static u64 __attribute__((ms_abi)) shim_BitBlt(u64 dstdc, u64 x, u64 y, u64 cx,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* SetDIBitsToDevice: 不经内存 DC,直接把 DIB 位块贴上窗口 DC.
|
||||
* 语义(MSDN): (xSrc,ySrc) 是 DIB 源区域左下角(DIB 坐标系 y 向上),
|
||||
* startScan/numLines 描述 lpvBits 缓冲覆盖的扫描线区间,
|
||||
* (xDest,yDest,w,h) 是客户区目标矩形(y 向下).
|
||||
* bottom-up DIB: 缓冲行 0 = DIB 扫描线 startScan(从底数);
|
||||
* top-down DIB : 缓冲行 0 = 图像顶行 + startScan.
|
||||
* 仅支持 32bpp BI_RGB;返回实际拷贝的扫描线数. */
|
||||
static u64 __attribute__((ms_abi)) shim_SetDIBitsToDevice(
|
||||
u64 hdc, i32 xDest, i32 yDest, u32 w, u32 h,
|
||||
i32 xSrc, i32 ySrc, u32 startScan, u32 numLines,
|
||||
u64 bits_p, u64 bmi_p, u64 colorUse) {
|
||||
(void)colorUse;
|
||||
if (hdc != SHIM_HDC_WND) return 0; /* 仅支持窗口 DC 目标 */
|
||||
const struct limine_framebuffer *fb = shim_fb();
|
||||
if (!fb || !fb->address) return 0;
|
||||
if (fb->bpp != 32 && fb->bpp != 24) return 0;
|
||||
if (!bits_p || !bmi_p || w == 0 || h == 0) return 0;
|
||||
const u8 *bmi = (const u8 *)bmi_p;
|
||||
i32 bw = *(const i32 *)(bmi + 4); /* biWidth */
|
||||
i32 bh = *(const i32 *)(bmi + 8); /* biHeight(负=top-down) */
|
||||
u16 bpp = *(const u16 *)(bmi + 14); /* biBitCount */
|
||||
u32 comp = *(const u32 *)(bmi + 16); /* biCompression */
|
||||
if (bw <= 0 || bh == 0 || bpp != 32 || comp != 0 /* BI_RGB */) return 0;
|
||||
int topdown = 0;
|
||||
i32 H = bh;
|
||||
if (H < 0) { H = -H; topdown = 1; }
|
||||
|
||||
const u32 *bits = (const u32 *)bits_p;
|
||||
i32 dx0 = xDest + g_wnd_x;
|
||||
i32 dy0 = yDest + g_wnd_y;
|
||||
|
||||
u8 *fbb = (u8 *)fb->address;
|
||||
u32 rsh = fb->red_mask_shift, gsh = fb->green_mask_shift, bsh = fb->blue_mask_shift;
|
||||
u32 rsz = fb->red_mask_size ? fb->red_mask_size : 8;
|
||||
u32 gsz = fb->green_mask_size ? fb->green_mask_size : 8;
|
||||
u32 bsz = fb->blue_mask_size ? fb->blue_mask_size : 8;
|
||||
int fast = (fb->bpp == 32 && rsh == 16 && gsh == 8 && bsh == 0
|
||||
&& rsz == 8 && gsz == 8 && bsz == 8);
|
||||
|
||||
u32 copied = 0;
|
||||
for (u32 row = 0; row < h; row++) {
|
||||
/* 目标顶行 row=0 ← DIB 坐标 y=ySrc+h-1(源区域顶边) */
|
||||
i32 sy = ySrc + (i32)h - 1 - (i32)row;
|
||||
if (sy < 0 || sy >= H) continue;
|
||||
/* DIB 扫描线 sy → lpvBits 缓冲行 */
|
||||
i64 br = topdown ? ((i64)(H - 1 - sy) - (i32)startScan)
|
||||
: ((i64)sy - (i32)startScan);
|
||||
if (br < 0 || br >= (i64)numLines) continue;
|
||||
i32 fy = dy0 + (i32)row;
|
||||
if (fy < 0 || fy >= (i32)fb->height) continue;
|
||||
const u32 *src = bits + (u64)br * (u64)bw;
|
||||
u8 *dst_row = fbb + (u64)fy * fb->pitch;
|
||||
copied++;
|
||||
for (u32 col = 0; col < w; col++) {
|
||||
i32 sx = xSrc + (i32)col;
|
||||
if (sx < 0 || sx >= bw) continue;
|
||||
i32 fx = dx0 + (i32)col;
|
||||
if (fx < 0 || fx >= (i32)fb->width) continue;
|
||||
u32 px = src[sx];
|
||||
if (fast) {
|
||||
((u32 *)dst_row)[fx] = px;
|
||||
} else {
|
||||
u32 r = (px >> 16) & 0xFF, g = (px >> 8) & 0xFF, bl = px & 0xFF;
|
||||
u32 v = ((r >> (8 - rsz)) << rsh)
|
||||
| ((g >> (8 - gsz)) << gsh)
|
||||
| ((bl >> (8 - bsz)) << bsh);
|
||||
if (fb->bpp == 32) {
|
||||
((u32 *)dst_row)[fx] = v;
|
||||
} else {
|
||||
u8 *p = dst_row + (u64)fx * 3;
|
||||
p[0] = (u8)(v & 0xFF);
|
||||
p[1] = (u8)((v >> 8) & 0xFF);
|
||||
p[2] = (u8)((v >> 16) & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
shim_draw_cursor(fb);
|
||||
return copied;
|
||||
}
|
||||
|
||||
/* 未实现 stub(64位)— 日志告警(含调用点返回地址)并返回 0 */
|
||||
static u64 __attribute__((ms_abi)) shim_unimpl64(u64 a0, u64 a1, u64 a2, u64 a3) {
|
||||
(void)a0; (void)a1; (void)a2; (void)a3;
|
||||
@@ -1642,6 +1867,7 @@ static const pe_shim_entry g_shim_table[] = {
|
||||
{"gdi32.dll", "DeleteObject", (void*)shim_DeleteObject, 0},
|
||||
{"gdi32.dll", "DeleteDC", (void*)shim_DeleteDC, 0},
|
||||
{"gdi32.dll", "BitBlt", (void*)shim_BitBlt, 0},
|
||||
{"gdi32.dll", "SetDIBitsToDevice", (void*)shim_SetDIBitsToDevice, 0},
|
||||
{"gdi32.dll", "GetStockObject", (void*)shim_GetStockObject, 0},
|
||||
{"gdi32.dll", "GdiFlush", (void*)shim_GdiFlush, 0},
|
||||
/* msvcrt.dll */
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
pe/pe_shim.o: pe\pe_shim.c pe\pe_shim.h include\utsm\types.h \
|
||||
include\utsm\arena.h include\utsm\log.h pe\..\arch\x86_64\limine.h
|
||||
pe\pe_dll_manager.h pe\..\include\utsm\pe.h include\utsm\arena.h \
|
||||
include\utsm\log.h pe\..\arch\x86_64\limine.h
|
||||
pe\pe_shim.h:
|
||||
include\utsm\types.h:
|
||||
pe\pe_dll_manager.h:
|
||||
pe\..\include\utsm\pe.h:
|
||||
include\utsm\arena.h:
|
||||
include\utsm\log.h:
|
||||
pe\..\arch\x86_64\limine.h:
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
/* shim 伪模块句柄(LoadLibrary 对已知 shim DLL 返回值)。
|
||||
* 真实 DLL 句柄 = pe_dll_load 镜像基址,与此值域区分。 */
|
||||
#define PE_SHIM_FAKE_MODULE 0x10000020ULL
|
||||
|
||||
/* 32位 shim:从模拟栈读取参数(cdecl 语义,调用者清栈)。
|
||||
* esp 指向模拟栈(第一个参数在 esp[0])。返回值 = EAX。 */
|
||||
typedef u64 (*pe_shim_fn32)(void *esp);
|
||||
@@ -82,4 +86,23 @@ const char *pe_shim_get_cmdline(void);
|
||||
* 完成转换;base=0 表示非解释器上下文(原生 PE32+ 路径),gp() 恒等映射。 */
|
||||
void pe_shim_set_emu_base(u64 base);
|
||||
|
||||
/* ===== P5 窗口模式(desktop 嵌入)=====
|
||||
* pe_service 在 run_windowed 前调用 pe_shim_set_window_host 挂起配置;
|
||||
* pe_shim_init(run 开头)重置 shim 状态后应用该配置。host==NULL 或
|
||||
* host->surface==NULL 时保持全屏独占行为(默认)。 */
|
||||
struct pe_window_host; /* 定义见 utsm/pe.h */
|
||||
void pe_shim_set_window_host(const struct pe_window_host *host);
|
||||
|
||||
/* 窗口模式输入注入(仅窗口模式生效,全屏返回 -1)。
|
||||
* inject_scancode: set-1 扫描码(bit7=release),e0_prefix!=0 为 E0 扩展。
|
||||
* inject_pointer : surface 局部坐标 + 按钮位(bit0/1/2=L/R/M),
|
||||
* 内部与上次状态比较合成 MOUSEMOVE/BUTTON 边沿。
|
||||
* inject_input : 直接投递任意 Win32 消息(WM_CLOSE 等宿主控制消息)。 */
|
||||
int pe_shim_inject_scancode(u32 scancode, u32 e0_prefix);
|
||||
int pe_shim_inject_pointer(i32 x, i32 y, u32 buttons);
|
||||
int pe_shim_inject_input(u32 msg, u64 wparam, u64 lparam, i32 ptx, i32 pty);
|
||||
|
||||
/* 窗口模式是否激活(1=渲染目标为 host surface)。 */
|
||||
int pe_shim_window_mode(void);
|
||||
|
||||
#endif /* PE_SHIM_H */
|
||||
|
||||
Reference in New Issue
Block a user