feat: white cursor with black outline (desktop/login/firstInit) + fix hash patcher param

- outline = empty pixel with any 8-neighbour filled, stays inside cursor save region

- patch_login_hash.ps1: typed byte[] params + ASCII comments, default path fallback (was silently misbinding under some hosts)
This commit is contained in:
Linehu
2026-10-04 22:43:18 +08:00
parent b4d9c8e7ed
commit a570fe09b5
4 changed files with 53 additions and 18 deletions
+15
View File
@@ -130,6 +130,21 @@ void cursor_restore_bg(void) {
}
void cursor_draw(int mx, int my) {
/* 白色指针 + 黑色描边:描边 = 空心像素且 8 邻域有实心(不出保存区) */
for (int r = 0; r < CURSOR_SIZE; r++) {
for (int c = 0; c < CURSOR_SIZE; c++) {
if (cursor_shape[r][c]) continue;
int near = 0;
for (int dy = -1; dy <= 1 && !near; dy++) {
for (int dx = -1; dx <= 1; dx++) {
int rr = r + dy, cc = c + dx;
if (rr < 0 || rr >= CURSOR_SIZE || cc < 0 || cc >= CURSOR_SIZE) continue;
if (cursor_shape[rr][cc]) { near = 1; break; }
}
}
if (near) du_pixel(&g_fb, mx + c, my + r, 0xFF000000u);
}
}
for (int r = 0; r < CURSOR_SIZE; r++) {
for (int c = 0; c < CURSOR_SIZE; c++) {
if (cursor_shape[r][c]) {
+2 -2
View File
@@ -499,8 +499,8 @@ static void cursor_draw(u32 *fb, i64 mx, i64 my) {
cursor_bg_valid = 1;
cursor_cur_x = mx;
cursor_cur_y = my;
/* draw cursor shape(全白指针,深色描边改白) */
u32 white = 0xFFFFFFFF, dark = 0xFFFFFFFF;
/* draw cursor shape(白色指针 + 纯黑描边,'X'=描边 'O'=填充) */
u32 white = 0xFFFFFFFF, dark = 0xFF000000;
for (i64 y = 0; y < CUR_H; y++) {
i64 py = my + y;
if (py < 0 || (u64)py >= fb_h) continue;
+21
View File
@@ -350,6 +350,27 @@ static void cursor_restore_bg(u32 *fb) {
static void cursor_draw(u32 *fb, int mx, int my) {
u32 fg = 0xFFFFFFFF; /* 白色指针 */
/* 黑色描边:空心像素且 8 邻域有实心 */
for (int r = 0; r < CURSZ; r++) {
for (int c = 0; c < CURSZ; c++) {
if (cursor_shape[r][c]) continue;
int near = 0;
for (int dy = -1; dy <= 1 && !near; dy++) {
for (int dx = -1; dx <= 1; dx++) {
int rr = r + dy, cc = c + dx;
if (rr < 0 || rr >= CURSZ || cc < 0 || cc >= CURSZ) continue;
if (cursor_shape[rr][cc]) { near = 1; break; }
}
}
if (near) {
int x = mx + c, y = my + r;
if (x >= 0 && (u64)x < fb_w && y >= 0 && (u64)y < fb_h) {
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
line[x] = 0xFF000000u;
}
}
}
}
for (int r = 0; r < CURSZ; r++) {
for (int c = 0; c < CURSZ; c++) {
if (!cursor_shape[r][c]) continue;
+15 -16
View File
@@ -1,36 +1,34 @@
# patch_login_hash.ps1 — login.elf .text 防篡改哈希补丁
# 用法: powershell -File patch_login_hash.ps1 <login.elf>
# 计算 .text 段的 SHA256,写入 .hashseg 段(__expected_hash,32 字节)。
param([Parameter(Mandatory=$true)][string]$ElfPath)
# patch_login_hash.ps1 - patch login.elf .text SHA256 into .hashseg
# usage: powershell -File patch_login_hash.ps1 [login.elf]
param([string]$ElfPath = "..\..\SYSTEM\system\user\use\login.elf")
if (-not (Test-Path $ElfPath)) { Write-Error "not found: $ElfPath"; exit 1 }
if (-not (Test-Path $ElfPath)) { Write-Error ("not found: " + $ElfPath); exit 1 }
$bytes = [System.IO.File]::ReadAllBytes($ElfPath)
# ELF64 header: e_shoff @ 0x28 (u64), e_shentsize @ 0x3A (u16), e_shnum @ 0x3C (u16)
function U64($b, $o) { [UInt64]$b[$o] -bor ([UInt64]$b[$o+1] -shl 8) -bor ([UInt64]$b[$o+2] -shl 16) -bor ([UInt64]$b[$o+3] -shl 24) -bor ([UInt64]$b[$o+4] -shl 32) -bor ([UInt64]$b[$o+5] -shl 40) -bor ([UInt64]$b[$o+6] -shl 48) -bor ([UInt64]$b[$o+7] -shl 56) }
function U16($b, $o) { [UInt32]$b[$o] -bor ([UInt32]$b[$o+1] -shl 8) }
function U32($b, $o) { [UInt32]$b[$o] -bor ([UInt32]$b[$o+1] -shl 8) -bor ([UInt32]$b[$o+2] -shl 16) -bor ([UInt32]$b[$o+3] -shl 24) }
function U64([byte[]]$b, [int]$o) { [UInt64]$b[$o] -bor ([UInt64]$b[$o+1] -shl 8) -bor ([UInt64]$b[$o+2] -shl 16) -bor ([UInt64]$b[$o+3] -shl 24) -bor ([UInt64]$b[$o+4] -shl 32) -bor ([UInt64]$b[$o+5] -shl 40) -bor ([UInt64]$b[$o+6] -shl 48) -bor ([UInt64]$b[$o+7] -shl 56) }
function U16([byte[]]$b, [int]$o) { [UInt32]$b[$o] -bor ([UInt32]$b[$o+1] -shl 8) }
function U32([byte[]]$b, [int]$o) { [UInt32]$b[$o] -bor ([UInt32]$b[$o+1] -shl 8) -bor ([UInt32]$b[$o+2] -shl 16) -bor ([UInt32]$b[$o+3] -shl 24) }
$shoff = U64 $bytes 0x28
$shentsize = U16 $bytes 0x3A
$shnum = U16 $bytes 0x3C
$textOff = 0; $textSize = 0; $hashOff = 0
$shstr = $null
for ($i = 0; $i -lt $shnum; $i++) {
$sh = $shoff + $i * $shentsize
$nameIdx = U32 $bytes $sh
$shType = U32 $bytes ($sh + 4)
$shOffset = U64 $bytes ($sh + 24)
$shSize = U64 $bytes ($sh + 32)
# sh_name indexes .shstrtab; resolve names via that section lazily
if ($shType -eq 3 -and -not $shstr) { $shstrOff = $shOffset; $shstrSize = $shSize; $shstr = $bytes[$shstrOff..($shstrOff+$shstrSize-1)] }
if ($shType -eq 3 -and -not $shstr) { $shstr = $bytes[[int]$shOffset..[int]($shOffset+$shSize-1)] }
}
function Get-Name([int]$idx) {
function Get-SectName([byte[]]$strtab, [int]$idx) {
$end = $idx
while ($shstr[$end] -ne 0) { $end++ }
[System.Text.Encoding]::ASCII.GetString($shstr, $idx, $end - $idx)
while ($strtab[$end] -ne 0) { $end++ }
[System.Text.Encoding]::ASCII.GetString($strtab, $idx, $end - $idx)
}
for ($i = 0; $i -lt $shnum; $i++) {
@@ -39,7 +37,7 @@ for ($i = 0; $i -lt $shnum; $i++) {
$shType = U32 $bytes ($sh + 4)
$shOffset = U64 $bytes ($sh + 24)
$shSize = U64 $bytes ($sh + 32)
$nm = Get-Name $nameIdx
$nm = Get-SectName $shstr $nameIdx
if ($nm -eq '.text' -and $shType -eq 1) { $textOff = $shOffset; $textSize = $shSize }
if ($nm -eq '.hashseg') { $hashOff = $shOffset }
}
@@ -53,5 +51,6 @@ $hash = $sha.ComputeHash($textBytes)
[Array]::Copy($hash, 0, $bytes, [int]$hashOff, 32)
[System.IO.File]::WriteAllBytes($ElfPath, $bytes)
Write-Host "[patch_login_hash] .text($textSize B) SHA256 -> .hashseg @ $hashOff : $(($hash[0..3] | ForEach-Object { $_.ToString('x2') }) -join '')..."
$hex = ($hash[0..3] | ForEach-Object { $_.ToString('x2') }) -join ''
Write-Host (".text(" + $textSize + " B) SHA256 -> .hashseg @ " + $hashOff + " : " + $hex + "...")
exit 0