286 lines
5.4 KiB
NASM
286 lines
5.4 KiB
NASM
; Mountain 3 crash diagnostics (German groove.exe). nasm -f bin -DCAVE=.. -DDATA=.. -DFIX=0/1
|
|
bits 32
|
|
org CAVE
|
|
%define D(o) dword [DATA+o]
|
|
; DATA layout: 0 magic, 16 cnt_parent_ok, 20 cnt_stale_addr, 24 cnt_stale_pop, 28 cnt_free, 32 cnt_anom,
|
|
; 36 cnt_alloc, 40 stale ring idx, 44 all ring idx, 48 dummy, 52 last free ptr, 56 last alloc size, 60 tmp idx,
|
|
; 64 stale ring 32x32, 1088 anomaly record 64 bytes, 1152 dump 256 bytes (hdr-128..+128), 1408 all-ring 64x32 (2048)
|
|
; 3456 free history 64 x 16
|
|
entry_addr: jmp near push_addr
|
|
entry_pop: jmp near pop_var
|
|
entry_free: jmp near free_hook
|
|
entry_alloc: jmp near alloc_hook
|
|
|
|
push_addr:
|
|
mov eax,[esp+4]
|
|
mov ecx,[eax+0xc]
|
|
mov edx,[esp+8]
|
|
mov [DATA+60],edx
|
|
mov edx,0x11
|
|
call record_all
|
|
test ecx,ecx
|
|
jz .stale
|
|
cmp dword [ecx+0xec],0
|
|
jz .stale
|
|
inc D(16)
|
|
.ok:
|
|
mov edx,[ecx+0xf4]
|
|
mov ecx,[esp+8]
|
|
lea edx,[edx+ecx*4]
|
|
.push:
|
|
push edx
|
|
push eax
|
|
call 0x54bbd0
|
|
add esp,8
|
|
ret
|
|
.stale:
|
|
inc D(20)
|
|
mov edx,1
|
|
call record
|
|
call stale_info
|
|
call check_heap
|
|
%if FIX
|
|
mov edx,DATA+48
|
|
jmp .push
|
|
%else
|
|
test ecx,ecx
|
|
jnz .ok
|
|
mov edx,DATA+48
|
|
jmp .push
|
|
%endif
|
|
|
|
pop_var:
|
|
push esi
|
|
mov esi,[esp+8]
|
|
push esi
|
|
call 0x54bc00
|
|
add esp,4
|
|
mov ecx,[esi+0xc]
|
|
mov edx,[esp+0xc]
|
|
mov [DATA+60],edx
|
|
push eax
|
|
mov eax,esi
|
|
mov edx,0x12
|
|
call record_all
|
|
pop eax
|
|
test ecx,ecx
|
|
jz .stale
|
|
cmp dword [ecx+0xec],0
|
|
jz .stale
|
|
inc D(16)
|
|
.ok:
|
|
mov edx,[ecx+0xf4]
|
|
mov ecx,[esp+0xc]
|
|
lea edx,[edx+ecx*4]
|
|
.store:
|
|
pop esi
|
|
mov [edx],eax
|
|
ret
|
|
.stale:
|
|
inc D(24)
|
|
push eax
|
|
mov eax,esi
|
|
mov edx,2
|
|
call record
|
|
call stale_info
|
|
call check_heap
|
|
pop eax
|
|
%if FIX
|
|
mov edx,DATA+48
|
|
jmp .store
|
|
%else
|
|
test ecx,ecx
|
|
jnz .ok
|
|
mov edx,DATA+48
|
|
jmp .store
|
|
%endif
|
|
|
|
; record: eax strat, ecx parent, edx kind, [DATA+60] idx. Preserves eax, ecx.
|
|
record:
|
|
push esi
|
|
push edi
|
|
push ebx
|
|
mov esi,[DATA+40]
|
|
and esi,31
|
|
shl esi,5
|
|
lea edi,[DATA+64+esi]
|
|
jmp rec_common
|
|
record_all:
|
|
push esi
|
|
push edi
|
|
push ebx
|
|
mov esi,[DATA+44]
|
|
and esi,63
|
|
shl esi,5
|
|
lea edi,[DATA+1408+esi]
|
|
inc D(44)
|
|
dec D(40) ; compensated below
|
|
rec_common:
|
|
inc D(40)
|
|
mov [edi],eax
|
|
mov [edi+4],ecx
|
|
mov [edi+8],edx
|
|
mov ebx,[DATA+60]
|
|
mov [edi+12],ebx
|
|
mov ebx,[eax+0x18]
|
|
mov [edi+16],ebx
|
|
mov dword [edi+20],0
|
|
mov dword [edi+24],0
|
|
mov dword [edi+28],0
|
|
test ecx,ecx
|
|
jz .np
|
|
mov ebx,[ecx+0x18]
|
|
mov [edi+20],ebx
|
|
mov ebx,[ecx+0xf4]
|
|
mov [edi+24],ebx
|
|
mov ebx,[ecx+0xec]
|
|
mov [edi+28],ebx
|
|
.np:
|
|
pop ebx
|
|
pop edi
|
|
pop esi
|
|
ret
|
|
|
|
free_hook:
|
|
pushad
|
|
inc D(28)
|
|
mov eax,[esp+36]
|
|
mov [DATA+52],eax
|
|
mov esi,[DATA+28]
|
|
and esi,63
|
|
shl esi,4
|
|
mov [DATA+3456+esi],eax
|
|
mov ebx,[esp+32] ; caller
|
|
mov [DATA+3456+esi+4],ebx
|
|
mov ebx,[eax-4] ; size|used
|
|
mov [DATA+3456+esi+8],ebx
|
|
mov ebx,[eax-12] ; next
|
|
mov [DATA+3456+esi+12],ebx
|
|
call check_heap
|
|
popad
|
|
mov eax,[esp+4]
|
|
push esi
|
|
jmp 0x41ada5
|
|
|
|
alloc_hook:
|
|
pushad
|
|
inc D(36)
|
|
mov eax,[esp+36]
|
|
mov [DATA+56],eax
|
|
call check_heap
|
|
popad
|
|
mov ecx,[0x58499c]
|
|
jmp 0x41ae26
|
|
|
|
; walks the local heap; on the first inconsistency records it (code in anomaly+0)
|
|
check_heap:
|
|
pushad
|
|
mov esi,[0x58499c]
|
|
test esi,esi
|
|
jz .done
|
|
xor edi,edi
|
|
mov ecx,70000
|
|
.loop:
|
|
mov edx,1
|
|
cmp [esi+4],edi
|
|
jne .bad
|
|
mov edx,2
|
|
movzx eax,word [esi+10]
|
|
cmp eax,1
|
|
ja .bad
|
|
mov ebx,[esi]
|
|
test ebx,ebx
|
|
jz .done
|
|
mov edx,3
|
|
movzx eax,word [esi+8]
|
|
lea eax,[esi+eax*4+12]
|
|
cmp ebx,eax
|
|
jne .bad
|
|
mov edi,esi
|
|
mov esi,ebx
|
|
dec ecx
|
|
jnz .loop
|
|
.done:
|
|
popad
|
|
ret
|
|
.bad:
|
|
inc D(32)
|
|
cmp dword [DATA+32],1
|
|
jne .done
|
|
mov [DATA+1088],edx
|
|
mov [DATA+1092],esi
|
|
mov [DATA+1096],edi
|
|
mov eax,[esi]
|
|
mov [DATA+1100],eax
|
|
mov eax,[esi+4]
|
|
mov [DATA+1104],eax
|
|
mov eax,[esi+8]
|
|
mov [DATA+1108],eax
|
|
mov eax,[DATA+28]
|
|
mov [DATA+1112],eax
|
|
mov eax,[DATA+36]
|
|
mov [DATA+1116],eax
|
|
mov eax,[DATA+40]
|
|
mov [DATA+1120],eax
|
|
mov eax,[esp+32] ; return address of check_heap caller
|
|
mov [DATA+1124],eax
|
|
mov eax,[DATA+52]
|
|
mov [DATA+1128],eax
|
|
mov eax,[DATA+56]
|
|
mov [DATA+1132],eax
|
|
; dump 256 bytes from edi (previous header) if set, else esi-128
|
|
test edi,edi
|
|
jnz .src
|
|
lea edi,[esi-128]
|
|
.src:
|
|
mov esi,edi
|
|
lea edi,[DATA+1152]
|
|
mov ecx,64
|
|
rep movsd
|
|
jmp .done
|
|
|
|
; stale_info: ecx parent, [DATA+60] idx -> DATA+4480 + (n&31)*16: target, block hdr, size|used, value before
|
|
stale_info:
|
|
pushad
|
|
test ecx,ecx
|
|
jz .out
|
|
mov edi,[ecx+0xf4]
|
|
mov eax,[DATA+60]
|
|
lea edi,[edi+eax*4]
|
|
mov ebx,[DATA+40]
|
|
dec ebx
|
|
and ebx,31
|
|
shl ebx,4
|
|
lea ebx,[DATA+4480+ebx]
|
|
mov [ebx],edi
|
|
mov eax,[edi]
|
|
mov [ebx+12],eax
|
|
mov dword [ebx+4],0
|
|
mov dword [ebx+8],0
|
|
mov esi,[0x58499c]
|
|
mov ecx,70000
|
|
.l:
|
|
test esi,esi
|
|
jz .out
|
|
mov edx,[esi]
|
|
test edx,edx
|
|
jnz .h
|
|
movzx eax,word [esi+8]
|
|
lea edx,[esi+eax*4+12]
|
|
.h:
|
|
cmp edi,esi
|
|
jb .next
|
|
cmp edi,edx
|
|
jae .next
|
|
mov [ebx+4],esi
|
|
mov eax,[esi+8]
|
|
mov [ebx+8],eax
|
|
jmp .out
|
|
.next:
|
|
mov esi,[esi]
|
|
dec ecx
|
|
jnz .l
|
|
.out:
|
|
popad
|
|
ret
|