#!perl -w # (C) 2003-2007 Willem Jan Hengeveld # Web: http://www.xs4all.nl/~itsme/ # http://wiki.xda-developers.com/ # # $Id: parsecrash420.pl 1754 2008-03-17 09:15:46Z itsme $ # use strict; use IO::File; use Carp qw(croak verbose); use Getopt::Long qw(:config no_ignore_case); use Dumpvalue; my $d= new Dumpvalue; $|=1; # find the tlb by looking for 'vfffd0000' in the output of 'pmemmap -v' # magician: # load 0xa0000000 allram.nb # tlb 0xa0660000 # # typhoon: # load 0x20001000 4640.mem # load 0x10000000 8300.mem # load 0x10200000 8c00.mem # load 0x20000000 8e00.mem # load 0x11d00000 8f10.mem # tlb 0x10200000 # # himalaya: # 0xfffd0000 -> 0x901c0000 TLB # 0xffff0000 -> 0x901c4000 vectors # 0xffffc000 -> 0x901c5000 Kdata # # c:/local/WINCE420/PUBLIC/COMMON/SDK/INC/winnt.h # IMAGE_DOS_HEADER # c:/local/WINCE420/PUBLIC/COMMON/SDK/INC/kfuncs.h # SH_* # c:/local/wince420/PUBLIC/COMMON/OAK/INC/romldr.h # ROMHDR, TOCentry, FILESentry # c:/local/wince420/PRIVATE/WINCEOS/COREOS/NK/INC/kernel.h # cinfo APISet MemBlock CALLSTACK openexe_t # Thread PGPOOL_Q Process Module FSMAP HDATA # # c:/local/wince420/PRIVATE/WINCEOS/COREOS/NK/INC/nkarm.h # KDataStruct _CPUCONTEXT # # c:/local/wince420/PRIVATE/WINCEOS/COREOS/NK/INC/schedule.h # PROXY EVENT CRIT MUTEX SEMAPHORE CLEANEVENT # # c:/local/wince420/PUBLIC/COMMON/OAK/INC/pehdr.h # e32_lite o32_lite info e32_exe # # c:/local/wince420/PUBLIC/COMMON/SDK/INC/winbase.h # CRITICAL_SECTION # # c:/local/wince420/PUBLIC/COMMON/OAK/INC/pkfuncs.h # KINX_* constants # # c:/local/wince420/PUBLIC/COMMON/SDK/INC/winioctl.h # FILE_DEVICE_* constants # my %syms; my %structs= ( char=> {size=>1, format=>'%s'}, wchar=>{size=>2, format=>'%s'}, BYTE=> {size=>1, format=>'%02x'}, WORD=> {size=>2, format=>'%04x'}, DWORD=>{size=>4, format=>'%08lx'}, ); readsymbols(); #$d->dumpValue(\%structs); sub readsymbols { my $curtype= ""; my $curstruct= ""; while () { if (/^!struct\s(\w+)/) { $curstruct= $1; $curtype= undef; $structs{$curstruct}= {size=>0, items=>{}}; } elsif (/^!(\w+)/) { $curtype= $1; $curstruct= undef; } elsif ($curtype && /^(\w+)\s+(\w+)/) { $syms{$curtype}{$2}= eval($1); } elsif ($curstruct && /^(\w+)\s+(\*)?(\w+)(?:@(\d+))?\s+(\w+)/) { my ($ofs, $ptrflag, $type, $count, $itemname)= (eval($1), $2, $3, $4 || 1, $5); my $ptype; if ($ptrflag) { $ptype= $type; $type= "DWORD"; } $structs{$curstruct}{items}{$itemname}= { ofs=>$ofs, type=>$type, count=>$count, name=>$itemname, $ptrflag?(ptype=>$ptype):(), }; if (!exists $structs{$type}) { croak "unknown type $type in struct $curstruct\n"; } if ($structs{$curstruct}{size} != $ofs) { warn sprintf("offset-size mismatch: o=%08lx s=%08lx %s.%s\n", $ofs, $structs{$curstruct}{size}, $curstruct, $itemname); } $structs{$curstruct}{size} += $count * $structs{$type}{size}; } } } my %handletypes= ( FFSD=> { simpledump=>\&handleFFSD, structtype=>'FFSDinfo' }, HFSD=> { simpledump=>\&handleHFSD, structtype=>'FFSDinfo' }, W32D=> { simpledump=>\&handleW32D, structtype=>'fsopendev_t' }, W32H=> { simpledump=>\&handleW32H, structtype=>'W32Hinfo' }, PFSD=> { simpledump=>\&handlePFSD, structtype=>'FFSDinfo' }, BDEV=> { simpledump=>\&handleBDEV, structtype=>'BDEVinfo' }, STRG=> { simpledump=>\&handleSTRG, structtype=>'STRGinfo' }, FMAP=> { simpledump=>\&handleFMAP, structtype=>'FSMAP' }, PROC=> { structtype=>'PROCESS' }, THRD=> { structtype=>'THREAD' }, APIS=> { structtype=>'APISET' }, EVNT=> { structtype=>'EVENT' }, MUTX=> { structtype=>'MUTEX' }, SEMP=> { structtype=>'SEMAPHORE' }, DBOA=> { structtype=>'DBInfo' }, Sock=> { structtype=>'SocketInfo' }, ); my $img= PhysicalMemory->new(); my %dumptypes; my %dumpedstructs; my %dumpoffsets; my $doListProcesses= 0; my $doListKdata= 0; my $doDumpMemory= 0; my $doSaveSection= 0; my $doSectionOverview= 0; my $doListHandles= 0; my $g_verbose= 0; sub usage { return <<__EOF__ Usage: parsecrash [-d VOFS] [-p] [-k] [-s VADDR LEN file] cfgfile -p : list processes -k : list kdata -d : dump memory -s : save section -S : save all sections -h : list handles -o : section overview -v : verbose __EOF__ } GetOptions( "p"=>\$doListProcesses, "k"=>\$doListKdata, "d"=>\$doDumpMemory, "s"=>\$doSaveSection, "S"=> sub { $doSaveSection= 2; }, "h"=>\$doListHandles, "o"=>\$doSectionOverview, "v"=>\$g_verbose, ) or croak usage(); my $cfgname= shift || croak usage(); my $cfg= LoadConfig($cfgname); sub LoadConfig { my ($fn)= @_; my $fh= IO::File->new($fn, "r") or croak "LoadConfig $fn: $!\n"; my %cfg; while (<$fh>) { s/\s+$//; next if (/^$/); next if (/^\s*[#;]/); if (/load\s+(\w+)\s+(.*)/i) { push @{$cfg{images}}, { poffset=>eval($1), filename=>$2 }; } elsif (/tlb\s+(\w+)/i) { $cfg{PhysTLBOffset}= eval($1); } else { croak "unrecognized cfg line: $_\n"; } } $fh->close(); return \%cfg; } for (@{$cfg->{images}}) { $img->Load($_->{filename}, $_->{poffset}); } my $vimg= VirtualMemory->new($img, $cfg->{PhysTLBOffset}); $vimg->SetSectionTable(kdata('KINX_SECTIONS')); sub kdata { my $sym= shift; return $vimg->ReadDword($syms{kdata}{$sym}); } sub vmofs { my ($ofs, $vmbase)= @_; if ($vmbase && $ofs>=0x10000 && $ofs<0x02000000) { $ofs += $vmbase; } return $ofs; } sub ofsvm { my ($ofs)= @_; if ($ofs<0x80000000) { return $ofs&0xfe000000; } return 0; } sub structofs { my ($sym, $ofs, $vmbase)= @_; if ($vmbase && $ofs<0x02000000) { $ofs += $vmbase; } if ($sym =~ /^(\w+)\.(\w+)((?:\.|->).*)?$/) { my ($structname, $itemname, $subitems)= ($1, $2, $3); if (!exists $structs{$structname}) { croak "invalid structname $structname\n"; } if (!exists $structs{$structname}{items}{$itemname}) { croak "invalid itemname $structname.$itemname\n"; } my $item= $structs{$structname}{items}{$itemname}; if (!defined $subitems) { return $item->{ofs}+$ofs; } elsif ($subitems =~ /^\./) { return structofs("$item->{type}$subitems", $ofs+$item->{ofs}, $vmbase); } elsif ($subitems =~ /^->(.*)/) { return structofs("$item->{ptype}.$1", struct("$structname.$itemname", $ofs, $vmbase), $vmbase); } else { croak "invalid subitem spec: $sym\n"; } } else { croak "invalid struct spec: '$sym'\n"; } } sub struct { my ($sym, $ofs, $vmbase)= @_; #printf("struct(%s %08lx)\n", $sym, $ofs); if ($vmbase && $ofs<0x02000000) { $ofs += $vmbase; } if ($sym =~ /^(\w+)\.(\w+)((?:\.|->).*)?$/) { my ($structname, $itemname, $subitems)= ($1, $2, $3); if (!exists $structs{$structname}) { croak "invalid structname $structname\n"; } if (!exists $structs{$structname}{items}{$itemname}) { croak "invalid itemname $structname.$itemname\n"; } my $item= $structs{$structname}{items}{$itemname}; my @result; if (!defined $subitems) { if ($item->{type} eq "DWORD") { for (0..$item->{count}-1) { push @result, $vimg->ReadDword($ofs+4*$_+$item->{ofs}); } } elsif ($item->{type} eq "WORD") { for (0..$item->{count}-1) { push @result, $vimg->ReadWord($ofs+2*$_+$item->{ofs}); } } elsif ($item->{type} eq "BYTE") { for (0..$item->{count}-1) { push @result, $vimg->ReadByte($ofs+$_+$item->{ofs}); } } elsif ($item->{type} eq "char") { my @chars; for (0..$item->{count}-1) { my $char= $vimg->ReadByte($ofs+$_+$item->{ofs}); last if ($char==0); push @chars, $char; } #printf("char: @chars\n"); push @result, pack("C*", @chars); } elsif ($item->{type} eq "wchar") { my @chars; for (0..$item->{count}-1) { my $wchar= $vimg->ReadWord($ofs+$_*2+$item->{ofs}); last if ($wchar==0); push @chars, $wchar; } push @result, pack("U*", @chars); } else { croak "unknown primitive type in struct $sym: $item->{type}\n"; } } elsif ($subitems =~ /^\./) { if (exists $structs{$item->{type}}) { for (0..$item->{count}-1) { push @result, struct("$item->{type}$subitems", $ofs+$_*$structs{$item->{type}}{size}+$item->{ofs}, $vmbase); } } else { croak "could not resolve struct specifier $sym\n"; } } elsif ($subitems =~ /^->(.*)/) { for (0..$item->{count}-1) { push @result, struct("$item->{ptype}.$1", struct("$structname.$itemname", $ofs, $vmbase), $vmbase); } } else { croak "invalid subitem spec: $sym\n"; } if (@result==1) { return $result[0]; } else { return @result; } } else { croak "invalid struct spec: '$sym'\n"; } } if ($doListKdata) { for (sort { $syms{kdata}{$a} <=> $syms{kdata}{$b} } keys %{$syms{kdata}}) { eval { printf("%08lx %-20s %08lx\n", $syms{kdata}{$_}, $_, kdata($_)); }; } } if ($doListProcesses) { my $procbase= kdata('KINX_PROCARRAY'); printf("procbase= %08lx curproc=%08lx(%08lx) curthread=(%08lx)%08lx\n", $procbase, kdata('hCurProc'), kdata('pCurPrc'), kdata('hCurThread'), kdata('pCurThd')); if (!$procbase) { croak "could not find procbase\n"; } for (my $pi= 0 ; $pi<32 ; $pi++) { DumpProcessEntry($pi*0xd8+$procbase); } } if ($doDumpMemory) { croak "specify virtual address with -d\n" if (!@ARGV); my $addr= eval(shift); croak "specify virtual address with -d\n" if (!defined $addr); for (my $i= 0 ; $i<256 ; $i+=4) { printf("%08lx: ", $addr+$i) if (($i%16)==0); printf(" %08lx", $vimg->ReadDword($addr+$i)); printf("\n") if (($i%16)==12); } } if ($doSaveSection == 1) { croak "specify virtual address with -s\n" if (!@ARGV); my $addr= eval(shift); croak "specify virtual address with -s\n" if (!defined $addr); my $length= eval(shift); croak "specify length with -s\n" if (!defined $length); my $savefile= shift; croak "specify savefile with -s\n" if (!$savefile); my $fh= IO::File->new($savefile, "w") or croak "$savefile: $!\n"; binmode $fh; for (my $ofs= $addr ; $ofs < $addr + $length ; $ofs += 0x1000) { my $data; eval { $data= $vimg->ReadData($ofs, 0x1000); }; if (!$@) { $fh->print($data); } else { $fh->seek(0x1000, SEEK_CUR); } } } if ($doSaveSection == 2) { SaveAllSections(); } if ($doSectionOverview) { PrintSectionOverview(); } if ($doListHandles) { ListHandles(); } exit(0); sub isStartPtr { my $ofs= shift; return ((struct('HDATA.hValue', $ofs)&3)!=2); } sub handle2HData { my $h= shift; return kdata('handleBase')+($h&0x1ffffffc); } sub handleFFSD { my ($vmbase, $obj)= @_; return struct("FFSDinfo.pFileinfo->pFilename->name", $obj, $vmbase); } sub handleHFSD { my ($vmbase, $obj)= @_; return struct("FFSDinfo.pGtgtInfo->pWStrName->str", $obj, $vmbase); } sub handleW32D { my ($vmbase, $obj)= @_; return sprintf("%s%d:", struct("fsopendev_t.lpDev->type", $obj, $vmbase), struct("fsopendev_t.lpDev->index", $obj, $vmbase) ); } sub handleW32H { my ($vmbase, $obj)= @_; return sprintf("oid %08lx", struct("W32Hinfo.oid", $obj, $vmbase)); } sub handlePFSD { my ($vmbase, $obj)= @_; return "" if ($obj==1); return struct("FFSDinfo.name", $obj, $vmbase); } sub handleBDEV { my ($vmbase, $obj)= @_; return sprintf("%s - %s", struct("BDEVinfo.name1", $obj, $vmbase), struct("BDEVinfo.name2", $obj, $vmbase)); } sub handleSTRG { my ($vmbase, $obj)= @_; return sprintf("%s %s %s", struct("STRGinfo.pstorageinfo->devname", $obj, $vmbase), struct("STRGinfo.pstorageinfo->desc1", $obj, $vmbase), struct("STRGinfo.pstorageinfo->desc2", $obj, $vmbase)); } sub handleFMAP { my ($vmbase, $obj)= @_; return struct("FSMAP.name->name", $obj, $vmbase); } sub structdumper { my ($type, $vmbase, $ofs, $parent)= @_; return "(null)" if ($ofs==0); return sprintf("(null_%04lx)",$ofs) if ($ofs<0x10000); if ($type eq "CINFO") { # special handling for cinfo. $vmbase= struct("CINFO.pServer->dwVMBase", $ofs); } if ( exists $dumptypes{vmofs($ofs,$vmbase)} && $dumptypes{vmofs($ofs,$vmbase)} ne $type && $dumptypes{vmofs($ofs,$vmbase)} ne "APISET" && $type ne "CINFO") { # APISET = { CINFO + dword } warn sprintf("\n!%08lx : %s != %s - %s {%s}\n", $ofs, $dumptypes{vmofs($ofs,$vmbase)}, $type, $parent, join(", ", @{$dumpoffsets{vmofs($ofs,$vmbase)}}) ); } else { $dumptypes{vmofs($ofs,$vmbase)}= $type; } $dumpedstructs{vmofs($ofs, $vmbase)}++; my @itemstrs; for my $item (sort { $a->{ofs} <=> $b->{ofs} } values %{$structs{$type}{items}}) { my $dumppath= sprintf("%s->%s.%s:%08lx", $parent, $type, $item->{name}, $ofs); if (exists $item->{ptype}) { my @values= struct("$type.$item->{name}", $ofs, $vmbase); for my $ixval (0..$#values) { my $val= $values[$ixval]; next if (!$vimg->isValidPtr(vmofs($val, $vmbase))); push @{$dumpoffsets{vmofs($val,$vmbase)}}, sprintf("%s[%d]", $dumppath, $ixval); if ( exists $dumptypes{vmofs($val,$vmbase)} && $dumptypes{vmofs($val,$vmbase)} ne $item->{ptype} ) { warn sprintf("\n!%s:%08lx %s=%08lx: %s != %s - %s {%s}\n", $type, $ofs, $item->{name}, vmofs($val,$vmbase), $dumptypes{vmofs($val,$vmbase)}, $item->{ptype}, $parent, join(", ", @{$dumpoffsets{vmofs($ofs,$vmbase)}}) ); } else { $dumptypes{vmofs($val,$vmbase)}= $item->{ptype}; } } } elsif ($item->{type} eq "DWORD") { my @values= struct("$type.$item->{name}", $ofs, $vmbase); for my $ixval (0..$#values) { my $val= $values[$ixval]; next if (!$vimg->isValidPtr(vmofs($val, $vmbase))); # todo: add value index to offset string for items.count>1 push @{$dumpoffsets{vmofs($val,$vmbase)}}, sprintf("%s[%d]", $dumppath, $ixval); } } if (exists $structs{$item->{type}}{format}) { my @value= struct("$type.$item->{name}", $ofs, $vmbase); push @itemstrs, sprintf("%s=[%s]", $item->{name}, join(",", map { sprintf($structs{$item->{type}}{format}, $value[$_]) } (0..$#value))); } else { push @itemstrs, sprintf("%s=[%s]", $item->{name}, join(",", map { structdumper($item->{type}, $vmbase, structofs("$type.$item->{name}", $ofs, $vmbase)+$structs{$item->{type}}{size}*$_, sprintf("%s[%d]", $dumppath, $_)) } (0..$item->{count}-1))); } } return sprintf("%s:%s", $type, join(", ", @itemstrs)); } sub ListHandles { my $ha= handle2HData(kdata('hCurProc')); my $hi= $ha; do { if (isStartPtr($ha)) { $ha= struct('HDATA.fwd', $ha); } my $acname= struct('HDATA.pci->acName', $ha); printf("%08lx %-4s %08lx %08lx", $ha, $acname, struct('HDATA.hValue', $ha), struct('HDATA.pvObj', $ha)); $dumptypes{$ha}= "HDATA"; $dumpedstructs{$ha}++; if (!exists $handletypes{$acname}) { } else { if ($g_verbose) { print " ", structdumper($handletypes{$acname}{structtype}, struct('HDATA.pci->pServer', $ha) ? struct('HDATA.pci->pServer->dwVMBase', $ha) : 0, struct('HDATA.pvObj', $ha), sprintf("HDATA[%08lx].pvObj", $ha)); } elsif (exists $handletypes{$acname}{simpledump}) { print " ", $handletypes{$acname}{simpledump}( struct('HDATA.pci->pServer', $ha) ? struct('HDATA.pci->pServer->dwVMBase', $ha) : 0, struct('HDATA.pvObj', $ha)); } } print "\n"; $ha= struct('HDATA.fwd', $ha); } while ($hi != $ha); if ($g_verbose) { my $newcount; do { $newcount=0; for my $ofs (keys %dumpoffsets) { if (!exists $dumpedstructs{$ofs}) { eval { if (exists $dumptypes{$ofs}) { printf("%08lx##:%s{%s} %s\n", $ofs, $dumptypes{$ofs}, join(", ", @{$dumpoffsets{$ofs}}), structdumper($dumptypes{$ofs}, ofsvm($ofs), $ofs, sprintf("%s", $dumpoffsets{$ofs}[0]))); } else { printf("%08lx##{%s} %s\n", $ofs, join(", ", @{$dumpoffsets{$ofs}}), structdumper("DWLIST", ofsvm($ofs), $ofs, sprintf("%s", $dumpoffsets{$ofs}[0]))); } }; if ($@) { printf("%08lx!!!!!%s %s\n", $ofs, exists $dumptypes{$ofs}?$dumptypes{$ofs}:"", $@); } $dumpedstructs{$ofs}++; $newcount++; } } } while ($newcount); } } sub SaveAllSections { } sub PrintSectionOverview { my %phys; for my $ixSection (1..63, 0xb3) { my $pscn = $vimg->ReadDword(kdata('KINX_SECTIONS') + 4*$ixSection); if ($pscn!=0) { for my $ixBlock (0..511) { my $pmb = $vimg->ReadDword($pscn+4*$ixBlock); if ($pmb!=0 && $pmb!=1) { my $apages= struct("MemBlock.aPages", $pmb); for my $ixPage (0..15) { my $dwPage= $vimg->ReadDword($apages+4*$ixPage); if ($dwPage!=~0xf && $dwPage!=0) { if (exists $phys{$dwPage&0xfffff000} && $phys{$dwPage&0xfffff000}!=$ixSection) { printf("phys: %08lx = %02x %02x\n", $dwPage&0xfffff000, $ixSection, $phys{$dwPage&0xfffff000}); } $phys{$dwPage&0xfffff000}= $ixSection; } } } } } } my $prevval; my $previx; my $lastix; for my $ofs (sort {$a<=>$b} keys %phys) { if (!defined $prevval || $prevval!=$phys{$ofs}) { if (defined $prevval) { printf("%08lx-%08lx %02x\n", $previx, $lastix+0x1000, $prevval); } $prevval= $phys{$ofs}; $previx= $ofs; } $lastix= $ofs; } printf("%08lx-%08lx %02x\n", $previx, $lastix+0x1000, $prevval); } sub DumpOpenExe { my $addr= shift; my $type= struct('openexe_t.filetype', $addr); my $isoid= struct('openexe_t.bIsOID', $addr); if ($type==2) { # objstore printf("openexe: objectstore handle=%08lx pm=%04x %08lx", struct('openexe_t.handle', $addr), struct('openexe_t.pagemode', $addr), struct('openexe_t.offset', $addr)); } elsif ($type==3) {# romimage printf("openexe: TOCentry=%08lx pm=%04x %08lx", struct('openexe_t.handle', $addr), struct('openexe_t.pagemode', $addr), struct('openexe_t.offset', $addr)); } elsif ($type==4) {# extimage printf("openexe: ppfs handle=%08lx pm=%04x %08lx", struct('openexe_t.handle', $addr), struct('openexe_t.pagemode', $addr), struct('openexe_t.offset', $addr)); } if ($isoid) { printf(" oid=%08lx\n", struct('openexe_t.name', $addr)); } else { printf(" name=%s\n", struct('openexe_t.name->name', $addr)); } } sub DumpProcessEntry { my $addr= shift; return if (struct('PROCESS.dwVMBase', $addr)==0); my $nameptr= struct('PROCESS.lpszProcName', $addr); my $cmdlineptr= struct('PROCESS.pcmdline', $addr); #todo: # create object that translates process memory. printf("slot%02lx vmbase=%08lx hProc= %08lx name=%08lx:%s cmd=%08lx:%s\n", struct('PROCESS.procnum', $addr), struct('PROCESS.dwVMBase', $addr), struct('PROCESS.hProc', $addr), $nameptr, $vimg->ReadWString($nameptr), $cmdlineptr, $vimg->ReadWString($cmdlineptr)); DumpOpenExe(structofs('PROCESS.oe', $addr)); if (struct('PROCESS.pTh', $addr)) { DumpThreads(struct('PROCESS.pTh', $addr)); } } sub DumpThreads { my $firstaddr= shift; my $addr= $firstaddr; while (1) { DumpThread($addr); $addr= struct('THREAD.pNextInProc', $addr); last if ($addr==0 || $addr==$firstaddr); } } sub DumpThread { my $addr= shift; printf(" hTh=%08lx SP=%08lx LR=%08lx PC=%08lx prio=%02x.%02x start=%08lx kern=%08lx user=%08lx\n", struct('THREAD.hTh', $addr), struct('THREAD.ctx.reg_Sp', $addr), struct('THREAD.ctx.reg_Lr', $addr), struct('THREAD.ctx.reg_Pc', $addr), struct('THREAD.bBPrio', $addr), struct('THREAD.bCPrio', $addr), struct('THREAD.dwStartAddr', $addr), struct('THREAD.dwKernTime', $addr), struct('THREAD.dwUserTime', $addr) ); if ($g_verbose) { for (my $cs= struct('THREAD.pcstkTop', $addr) ; $cs ; $cs = struct('CALLSTACK.pcstkNext', $cs)) { printf("CALLSTACK proc=%08lx addr=%08lx sp=%08lx\n", struct('CALLSTACK.pprcLast',$cs)?struct('PROCESS.hProc',struct('CALLSTACK.pprcLast',$cs)):0, struct('CALLSTACK.retAddr',$cs), struct('CALLSTACK.dwPrevSP',$cs)); } } } package PhysicalMemory; use Carp; sub new { my ($class)= @_; return bless {}, $class; } sub Load { my ($self, $fn, $base)= @_; my $fh= IO::File->new($fn, "r") or croak "Physmem::Load $fn: $!\n"; binmode $fh; $self->{$base}= $fh; } sub FindFile { my ($self, $pofs)= @_; for (keys %$self) { if ($_ <= $pofs && $pofs < $_ + -s $self->{$_}) { return ($_, $self->{$_}); } } croak sprintf("PhysicalMemory::FileFile(%08lx) address is not mapped\n", $pofs); } sub ReadData { my ($self, $addr, $size)= @_; my @chunks; while ($size>0) { my ($base, $fh)= $self->FindFile($addr); if (!$fh) { croak sprintf("PhysicalMemory::ReadData(%08lx) address is not mapped\n", $addr); } $fh->seek($addr-$base, 0) or croak sprintf("PhysicalMemory::ReadData(%08lx): seek %08lx: %s\n", $addr, $addr-$base, $!); my $data; $fh->read($data, $size) or croak sprintf("PhysicalMemory::ReadData(%08lx): read %08lx: %s\n", $addr, $size, $!); push @chunks, $data; $size -= length($data); $addr += length($addr); } return join("", @chunks); } sub ReadByte { my ($self, $addr)= @_; return unpack("C", $self->ReadData($addr, 1)); } sub ReadWord { my ($self, $addr)= @_; return unpack("v", $self->ReadData($addr, 2)); } sub ReadDword { my ($self, $addr)= @_; return unpack("V", $self->ReadData($addr, 4)); } sub ReadString { my ($self, $addr)= @_; my $data= $self->ReadData($addr, 64); $data =~ s/\x00.*//; return $data; } sub ReadWString { my ($self, $addr)= @_; if ($addr==0) { return "(pnull)"; } my $data= $self->ReadData($addr, 128); $data= substr($data, 0, index($data, "\x00\x00\x00")+1); $data= pack("C*", unpack("v*", $data)); return "\"".$data."\""; } package VirtualMemory; use Carp; # fedcba9876543210fedcba9876543210 # .ssssssbbbbbbbbbpppp............ sub VA_SECTION { 25 } sub SECTION_MASK { 0x3f } sub VA_BLOCK { 16 } sub BLOCK_MASK { 0x1ff } sub VA_PAGE { 12 } sub PAGE_MASK { 0xf } sub BAD_PAGE { ~0xf } sub NULL_BLOCK { 0 } sub RESERVED_BLOCK { 1 } sub new { my ($class, $img, $physTLBOfs, $virtSectionsOfs)= @_; my $self= bless { img=>$img, physTLBOfs=>$physTLBOfs, }, $class; return $self; } sub SetSectionTable { my ($self, $vofs)= @_; $self->{virtSectionsOfs}= $vofs; } sub PhysicalToVirtual { } sub VirtualToPhysical { my ($self, $vofs)= @_; if ($vofs<0x80000000 || ($vofs>=0xc2000000 && $vofs<0xc4000000)) { return $self->SectionVirtualToPhysical($vofs); } else { return $self->TLBVirtualToPhysical($vofs); } } sub SectionVirtualToPhysical { my ($self, $vofs)= @_; my $ixSection= ($vofs >> VA_SECTION); $ixSection= 0xb3 if ($ixSection==0x62); # SECURE_SECTION -> KINX_NKSECTION my $ixBlock = ($vofs >> VA_BLOCK) & BLOCK_MASK; my $ixPage = ($vofs >> VA_PAGE) & PAGE_MASK; my $pscn = $self->ReadDword($self->{virtSectionsOfs} + 4*$ixSection); my $pmb = $self->ReadDword($pscn+4*$ixBlock); if ($pmb==NULL_BLOCK) { croak sprintf("SectionVirtualToPhysical(%08lx) : NULL_BLOCK", $vofs); } if ($pmb==RESERVED_BLOCK) { croak sprintf("SectionVirtualToPhysical(%08lx) : RESERVED_BLOCK", $vofs); } my $apages= main::struct("MemBlock.aPages", $pmb); my $dwPageentry= $self->ReadDword($apages+4*$ixPage); if ($dwPageentry==BAD_PAGE) { croak sprintf("SectionVirtualToPhysical(%08lx) : BAD_PAGE", $vofs); } if ($dwPageentry==0 ) { croak sprintf("SectionVirtualToPhysical(%08lx) : NULL_PAGE", $vofs); } if (($dwPageentry&0xfff00000)==0xfff00000) { croak sprintf("SectionVirtualToPhysical(%08lx) : invalid memory", $vofs); } return ($vofs&0xfff)|($dwPageentry&0xfffff000); } sub isValidPtr { my ($self, $vofs)= @_; return 0 if ($vofs<0x10000); return 0 if ($vofs&3); eval { $self->VirtualToPhysical($vofs); }; return (!$@); } sub TLBVirtualToPhysical { my ($self, $vofs)= @_; my $firstLevelIndex= $vofs>>20; my $firstLevelDescriptor= $self->{img}->ReadDword($self->{physTLBOfs}+$firstLevelIndex*4); for ($firstLevelDescriptor&3) { if ($_==0) { croak sprintf("v2p1 %08lx : %08lx -> ignore entry\n", $vofs, $firstLevelDescriptor); } elsif ($_==1) { return $self->CoarseEntry($vofs, $firstLevelDescriptor); } elsif ($_==2) { return $self->SectionEntry($vofs, $firstLevelDescriptor); } elsif ($_==3) { return $self->FineEntry($vofs, $firstLevelDescriptor); } } } sub CoarseEntry { my ($self, $vofs, $firstLevelDescriptor)= @_; my $secondLevelIndex= ($vofs>>12)&0xff; my $pagetable= $firstLevelDescriptor&0xfffffc00; my $secondLevelDescriptor= $self->{img}->ReadDword($pagetable+$secondLevelIndex*4); return $self->SecondLevelPagetable($vofs, $secondLevelDescriptor); } sub SectionEntry { my ($self, $vofs, $firstLevelDescriptor)= @_; my $sectionbase= $firstLevelDescriptor&0xfff00000; return $sectionbase | ($vofs&0xfffff); } sub FineEntry { my ($self, $vofs, $firstLevelDescriptor)= @_; my $secondLevelIndex= ($vofs>>10)&0x3ff; my $pagetable= $firstLevelDescriptor&0xfffff000; my $secondLevelDescriptor= $self->{img}->ReadDword($pagetable+$secondLevelIndex*4); return $self->SecondLevelPagetable($vofs, $secondLevelDescriptor); } sub SecondLevelPagetable { my ($self, $vofs, $secondLevelDescriptor)= @_; for ($secondLevelDescriptor&3) { if ($_==0) { croak sprintf("v2p2: %08lx : %08lx -> ignore entry\n", $vofs, $secondLevelDescriptor); } elsif ($_==1) { return $self->LargePage($vofs, $secondLevelDescriptor); } elsif ($_==2) { return $self->SmallPage($vofs, $secondLevelDescriptor); } elsif ($_==3) { return $self->TinyPage($vofs, $secondLevelDescriptor); } } } sub LargePage { my ($self, $vofs, $secondLevelDescriptor)= @_; return ($secondLevelDescriptor&0xffff0000) | ($vofs&0xffff); } sub SmallPage { my ($self, $vofs, $secondLevelDescriptor)= @_; return ($secondLevelDescriptor&0xfffff000) | ($vofs&0xfff); } sub TinyPage { my ($self, $vofs, $secondLevelDescriptor)= @_; return ($secondLevelDescriptor&0xfffffc00) | ($vofs&0x3ff); } ############################### # todo: these functions don't handle page boundaries. sub ReadData { my ($self, $vofs, @args)= @_; return $self->{img}->ReadData($self->VirtualToPhysical($vofs), @args); } sub ReadByte { my ($self, $vofs, @args)= @_; return $self->{img}->ReadByte($self->VirtualToPhysical($vofs), @args); } sub ReadWord { my ($self, $vofs, @args)= @_; return $self->{img}->ReadWord($self->VirtualToPhysical($vofs), @args); } sub ReadDword { my ($self, $vofs, @args)= @_; return $self->{img}->ReadDword($self->VirtualToPhysical($vofs), @args); } sub ReadString { my ($self, $vofs, @args)= @_; return $self->{img}->ReadString($self->VirtualToPhysical($vofs), @args); } sub ReadWString { my ($self, $vofs, @args)= @_; if ($vofs==0) { return "(vnull)"; } my $str; eval { $str= $self->{img}->ReadWString($self->VirtualToPhysical($vofs), @args); }; if ($@) { return "(invalid)"; } return $str; } package main; __DATA__ !kdata 0xFFFD0000 firstpagetabel 0xFFFE0000 secondpagetabel 0xFFFF0000 exceptionvectors 0xFFFFC800 lpvTls Current thread local storage pointer 0xFFFFC804 ahSys_W32 0xFFFFC808 hCurThread 0xFFFFC80C hCurProc 0xFFFFC810 ahSys_KW32 0xFFFFC884 bResched reschedule flag 0xFFFFC885 cNest kernel exception nesting 0xFFFFC886 bPowerOff TRUE during "power off" processing 0xFFFFC887 bProfileOn TRUE if profiling enabled 0xFFFFC888 unused 0xFFFFC88C rsvd2 was DiffMSec 0xFFFFC890 pCurPrc ptr to current PROCESS struct 0xFFFFC894 pCurThd ptr to current THREAD struct 0xFFFFC898 dwKCRes 0xFFFFC89C handleBase handle table base address 0xFFFFC8A0 aSections section table for virutal memory 0xFFFFC9A0 alpeIntrEvents 0xFFFFCA20 alpvIntrData 0xFFFFCAA0 pAPIReturn direct API return address for kernel mode 0xFFFFCAA4 pMap ptr to MemoryMap array 0xFFFFCAA8 dwInDebugger !0 when in debugger 0xFFFFCAAC pCurFPUOwner current FPU owner 0xFFFFCAB0 pCpuASIDPrc current ASID proc 0xFFFFCAB4 nMemForPT Memory used for PageTables 0xFFFFCAB8 alPad 0xFFFFCB00 KINX_PROCARRAY address of process array 0xFFFFCB04 KINX_PAGESIZE system page size 0xFFFFCB08 KINX_PFN_SHIFT shift for page # in PTE 0xFFFFCB0C KINX_PFN_MASK mask for page # in PTE 0xFFFFCB10 KINX_PAGEFREE # of free physical pages 0xFFFFCB14 KINX_SYSPAGES # of pages used by kernel 0xFFFFCB18 KINX_KHEAP ptr to kernel heap array 0xFFFFCB1C KINX_SECTIONS ptr to SectionTable array 0xFFFFCB20 KINX_MEMINFO ptr to system MemoryInfo struct 0xFFFFCB24 KINX_MODULES ptr to module list 0xFFFFCB28 KINX_DLL_LOW lower bound of DLL shared space 0xFFFFCB2C KINX_NUMPAGES total # of RAM pages 0xFFFFCB30 KINX_PTOC ptr to ROM table of contents points to ROMHDR struct 0xFFFFCB34 KINX_KDATA_ADDR kernel mode version of KData 0xFFFFCB38 KINX_GWESHEAPINFO Current amount of gwes heap in use 0xFFFFCB3C KINX_TIMEZONEBIAS Fast timezone bias info 0xFFFFCB40 KINX_PENDEVENTS bit mask for pending interrupt events 0xFFFFCB44 KINX_KERNRESERVE number of kernel reserved pages 0xFFFFCB48 KINX_API_MASK bit mask for registered api sets 0xFFFFCB4C KINX_NLS_CP hiword OEM code page, loword ANSI code page 0xFFFFCB50 KINX_NLS_SYSLOC Default System locale 0xFFFFCB54 KINX_NLS_USERLOC Default User locale 0xFFFFCB58 KINX_HEAP_WASTE Kernel heap wasted space 0xFFFFCB5C KINX_DEBUGGER For use by debugger for protocol communication 0xFFFFCB60 KINX_APISETS APIset pointers 0xFFFFCB64 KINX_MINPAGEFREE water mark of the minimum number of free pages 0xFFFFCB68 KINX_CELOGSTATUS CeLog status flags 0xFFFFCB6C KINX_NKSECTION Address of NKSection 0xFFFFCB70 KINX_PWR_EVTS Events to be set after power on 0xFFFFCB74 KINX_29 0xFFFFCB78 KINX_30 0xFFFFCB7C KINX_NKSIG last entry of KINFO -- signature when NK is ready !handletypes 0x00 SH_WIN32 0x01 SH_CURTHREAD 0x02 SH_CURPROC 0x04 HT_EVENT // Event handle type 0x05 HT_MUTEX // Mutex handle type 0x06 HT_APISET // kernel API set handle type 0x07 HT_FILE // open file handle type 0x08 HT_FIND // FindFirst handle type 0x09 HT_DBFILE // open database handle type 0x0a HT_DBFIND // database find handle type 0x0b HT_SOCKET // WinSock open socket handle type 0x0c HT_INTERFACE 0x0d HT_SEMAPHORE // Semaphore handle type 0x0e HT_FSMAP // mapped files 0x0f HT_WNETENUM // Net Resource Enumeration 0x10 SH_GDI 0x11 SH_WMGR 0x12 SH_WNET 0x13 SH_COMM 0x14 SH_FILESYS_APIS 0x15 SH_SHELL 0x16 SH_DEVMGR_APIS 0x17 SH_TAPI 0x18 SH_PATCHER 0x1a SH_SERVICES !e32infotypes 0x00 EXP // Export Directory 0x01 IMP // Import Directory 0x02 RES // Resource Directory 0x03 EXC // Exception Directory 0x04 SEC // Certificates Directory 0x05 FIX // Base Relocation Directory 0x06 DEB // Debug Directory 0x07 IMD // Architecture Directory 0x08 MSP // Global Pointer Directory 0x09 TLS // Thread Storage Directory 0x0a CBK // Load Configuration Directory 0x0b RS1 // Bound Import Directory 0x0c RS2 // Import Address Table Directory 0x0d RS3 // Delay Import Directory 0x0e RS4 // COM Descriptor Directory 0x0f RS5 // Reserved Directory !file_device_types 0x0001 FILE_DEVICE_BEEP 0x0002 FILE_DEVICE_CD_ROM 0x0003 FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x0004 FILE_DEVICE_CONTROLLER 0x0005 FILE_DEVICE_DATALINK 0x0006 FILE_DEVICE_DFS 0x0007 FILE_DEVICE_DISK 0x0008 FILE_DEVICE_DISK_FILE_SYSTEM 0x0009 FILE_DEVICE_FILE_SYSTEM 0x000a FILE_DEVICE_INPORT_PORT 0x000b FILE_DEVICE_KEYBOARD 0x000c FILE_DEVICE_MAILSLOT 0x000d FILE_DEVICE_MIDI_IN 0x000e FILE_DEVICE_MIDI_OUT 0x000f FILE_DEVICE_MOUSE 0x0010 FILE_DEVICE_MULTI_UNC_PROVIDER 0x0011 FILE_DEVICE_NAMED_PIPE 0x0012 FILE_DEVICE_NETWORK 0x0013 FILE_DEVICE_NETWORK_BROWSER 0x0014 FILE_DEVICE_NETWORK_FILE_SYSTEM 0x0015 FILE_DEVICE_NULL 0x0016 FILE_DEVICE_PARALLEL_PORT 0x0017 FILE_DEVICE_PHYSICAL_NETCARD 0x0018 FILE_DEVICE_PRINTER 0x0019 FILE_DEVICE_SCANNER 0x001a FILE_DEVICE_SERIAL_MOUSE_PORT 0x001b FILE_DEVICE_SERIAL_PORT 0x001c FILE_DEVICE_SCREEN 0x001d FILE_DEVICE_SOUND 0x001e FILE_DEVICE_STREAMS 0x001f FILE_DEVICE_TAPE 0x0020 FILE_DEVICE_TAPE_FILE_SYSTEM 0x0021 FILE_DEVICE_TRANSPORT 0x0022 FILE_DEVICE_UNKNOWN 0x0023 FILE_DEVICE_VIDEO 0x0024 FILE_DEVICE_VIRTUAL_DISK 0x0025 FILE_DEVICE_WAVE_IN 0x0026 FILE_DEVICE_WAVE_OUT 0x0027 FILE_DEVICE_8042_PORT 0x0028 FILE_DEVICE_NETWORK_REDIRECTOR 0x0029 FILE_DEVICE_BATTERY 0x0029 FILE_DEVICE_PARTITION 0x002a FILE_DEVICE_BUS_EXTENDER 0x002b FILE_DEVICE_MODEM 0x002c FILE_DEVICE_VDM 0x002d FILE_DEVICE_MASS_STORAGE 0x002e FILE_DEVICE_SMB 0x002f FILE_DEVICE_KS 0x0030 FILE_DEVICE_CHANGER 0x0030 FILE_DEVICE_STORE 0x0031 FILE_DEVICE_SMARTCARD 0x0032 FILE_DEVICE_ACPI 0x0032 FILE_DEVICE_POWER 0x0033 FILE_DEVICE_DVD 0x0034 FILE_DEVICE_FULLSCREEN_VIDEO 0x0035 FILE_DEVICE_DFS_FILE_SYSTEM 0x0036 FILE_DEVICE_DFS_VOLUME 0x0101 FILE_DEVICE_HAL 0x0102 FILE_DEVICE_CONSOLE 0x0103 FILE_DEVICE_PSL 0x0104 FILE_DEVICE_SERVICE !struct FILETIME 0x00 DWORD ftLow 0x04 DWORD ftHigh !struct wstr 0x00 wchar@260 str !struct CPUCONTEXT 0x0000 DWORD Psr 0x0004 DWORD reg_R0 0x0008 DWORD reg_R1 0x000c DWORD reg_R2 0x0010 DWORD reg_R3 0x0014 DWORD reg_R4 0x0018 DWORD reg_R5 0x001c DWORD reg_R6 0x0020 DWORD reg_R7 0x0024 DWORD reg_R8 0x0028 DWORD reg_R9 0x002c DWORD reg_R10 0x0030 DWORD reg_R11 0x0034 DWORD reg_R12 0x0038 DWORD reg_Sp 0x003c DWORD reg_Lr 0x0040 DWORD reg_Pc 0x0044 DWORD Fpscr 0x0048 DWORD FpExc 0x004c DWORD@33 S 0x00d0 DWORD@8 FpExtra !struct CALLSTACK 0x0000 *CALLSTACK pcstkNext 0x0004 DWORD retAddr /* return address */ 0x0008 *PROCESS pprcLast /* previous process */ 0x000c DWORD akyLast /* previous access key */ 0x0010 DWORD extra /* extra CPU dependent data */ 0x0014 DWORD dwPrevSP /* SP of caller */ 0x0018 DWORD dwPrcInfo /* information about the caller (mode, callback?, etc) */ !struct THREAD 0x0000 WORD wInfo; /* 00: various info about thread, see above */ 0x0002 BYTE bSuspendCnt; /* 02: thread suspend count */ 0x0003 BYTE bWaitState; /* 03: state of waiting loop */ 0x0004 *PROXY pProxList; /* 04: list of proxies to threads blocked on this thread */ 0x0008 *THREAD pNextInProc; /* 08: next thread in this process */ 0x000c *PROCESS pProc; /* 0C: pointer to current process */ 0x0010 *PROCESS pOwnerProc; /* 10: pointer to owner process */ 0x0014 DWORD aky; /* 14: keys used by thread to access memory & handles */ 0x0018 *CALLSTACK pcstkTop; /* 18: current api call info */ 0x001c DWORD dwOrigBase; /* 1C: Original stack base */ 0x0020 DWORD dwOrigStkSize; /* 20: Size of the original thread stack */ 0x0024 *DWORD tlsPtr; /* 24: tls pointer */ 0x0028 DWORD dwWakeupTime; /* 28: sleep count, also pending sleepcnt on waitmult */ 0x002c *DWORD tlsSecure; /* 2c: TLS for secure stack */ 0x0030 *DWORD tlsNonSecure; /* 30: TLS for non-secure stack */ 0x0034 *PROXY lpProxy; /* 34: first proxy this thread is blocked on */ 0x0038 DWORD dwLastError; /* 38: last error */ 0x003c DWORD hTh; /* 3C: Handle to this thread, needed by NextThread */ 0x0040 BYTE bBPrio; /* 40: base priority */ 0x0041 BYTE bCPrio; /* 41: curr priority */ 0x0042 WORD wCount; /* 42: nonce for blocking lists */ 0x0044 *THREAD pPrevInProc; /* 44: previous thread in this process */ 0x0048 DWORD pThrdDbg; /* 48: pointer to thread debug structure, if any */ 0x004c DWORD pSwapStack; /* 4c */ 0x0050 DWORD ftCreate_dwLowDateTime; /* 50: time thread is created */ 0x0054 DWORD ftCreate_dwHighDateTime; 0x0058 DWORD lpce; /* 58: cleanevent for unqueueing blocking lists */ - used to be 'CLEANEVENT' 0x005c DWORD dwStartAddr; /* 5c: thread PC at creation, used to get thread name */ 0x0060 CPUCONTEXT ctx; /* 60: thread's cpu context information */ 0x0150 *THREAD pNextSleepRun; /* ??: next sleeping thread, if sleeping, else next on runq if runnable */ 0x0154 *THREAD pPrevSleepRun; /* ??: back pointer if sleeping or runnable */ 0x0158 *THREAD pUpRun; /* ??: up run pointer (circulaar) */ 0x015c *THREAD pDownRun; /* ??: down run pointer (circular) */ 0x0160 *THREAD pUpSleep; /* ??: up sleep pointer (null terminated) */ 0x0164 *THREAD pDownSleep; /* ??: down sleep pointer (null terminated) */ 0x0168 DWORD pOwnedList; /* ??: list of crits and mutexes for priority inversion */ 0x016c DWORD@32 pOwnedHash; 0x01ec DWORD dwQuantum; /* ??: thread quantum */ 0x01f0 DWORD dwQuantLeft; /* ??: quantum left */ 0x01f4 *PROXY lpCritProxy; /* ??: proxy from last critical section block, in case stolen back */ 0x01f8 *PROXY lpPendProxy; /* ??: pending proxies for queueing */ 0x01fc DWORD dwPendReturn; /* ??: return value from pended wait */ 0x0200 DWORD dwPendTime; /* ??: timeout value of wait operation */ 0x0204 *THREAD pCrabPth; 0x0208 WORD wCrabCount; 0x020a WORD wCrabDir; 0x020c DWORD dwPendWakeup; /* ??: pending timeout */ 0x0210 WORD wCount2; /* ??: nonce for SleepList */ 0x0212 BYTE bPendSusp; /* ??: pending suspend count */ 0x0213 BYTE bDbgCnt; /* ??: recurse level in debug message */ 0x0214 DWORD hLastCrit; /* ??: Last crit taken, cleared by nextthread */ 0x0218 CALLSTACK IntrStk; 0x0234 DWORD dwKernTime; /* ??: elapsed kernel time */ 0x0238 DWORD dwUserTime; /* ??: elapsed user time */ !struct openexe_t 0x00 DWORD handle // object store handle 0x04 BYTE filetype 0x05 BYTE bIsOID 0x06 WORD pagemode 0x08 DWORD offset 0x0c *Name name !struct info 0x00 DWORD rva /* Virtual relative address of info */ 0x04 DWORD size /* Size of information block */ !struct e32_lite 0x00 WORD e32_objcnt /* Number of memory objects */ 0x02 BYTE e32_cevermajor /* version of CE built for */ 0x03 BYTE e32_ceverminor /* version of CE built for */ 0x04 DWORD e32_stackmax /* Maximum stack size */ 0x08 DWORD e32_vbase /* Virtual base address of module */ 0x0c DWORD e32_vsize /* Virtual size of the entire image */ 0x10 DWORD e32_sect14rva /* section 14 rva */ 0x14 DWORD e32_sect14size /* section 14 size */ # wce5: DWORD e32_timestamp; /* Time EXE/DLL was created/modified */ 0x18 info@6 e32_unit /* Array of extra info units */ # wce5: @7 ( including DEB section ) !struct o32_lite 0x00 DWORD o32_vsize 0x04 DWORD o32_rva 0x08 DWORD o32_realaddr 0x0c DWORD o32_access 0x10 DWORD o32_flags 0x14 DWORD o32_psize 0x18 DWORD o32_dataptr !struct PGPOOL_Q 0x00 WORD idxHead; /* head of the queue */ 0x02 WORD idxTail; /* tail of the queue */ !struct PROCESS 0x00 BYTE procnum /* 00: ID of this process [ie: it's slot number] */ 0x01 BYTE DbgActive /* 01: ID of process currently DebugActiveProcess'ing this process */ 0x02 BYTE bChainDebug /* 02: Did the creator want to debug child processes? */ 0x03 BYTE bTrustLevel /* 03: level of trust of this exe */ 0x04 *PROXY pProxList /* 04: list of proxies to threads blocked on this process */ 0x08 DWORD hProc /* 08: handle for this process, needed only for SC_GetProcFromPtr */ 0x0c DWORD dwVMBase /* 0C: base of process's memory section, or 0 if not in use */ 0x10 *THREAD pTh /* 10: first thread in this process */ 0x14 DWORD aky /* 14: default address space key for process's threads */ 0x18 DWORD BasePtr /* 18: Base pointer of exe load */ 0x1c DWORD hDbgrThrd /* 1C: handle of thread debugging this process, if any */ 0x20 *wstr lpszProcName /* 20: name of process */ 0x24 DWORD tlsLowUsed /* 24: TLS in use bitmask (first 32 slots) */ 0x28 DWORD tlsHighUsed /* 28: TLS in use bitmask (second 32 slots) */ 0x2c DWORD pfnEH /* 2C: process exception handler */ 0x30 DWORD ZonePtr /* 30: Debug zone pointer */ 0x34 *THREAD pMainTh /* 34 primary thread in this process*/ 0x38 *Module pmodResource /* 38: module that contains the resources */ 0x3c *Name@3 pStdNames /* 3C: Pointer to names for stdio */ 0x48 *wstr pcmdline /* 48: Pointer to command line */ 0x4c DWORD dwDyingThreads /* 4C: number of pending dying threads */ 0x50 openexe_t oe /* 50: Pointer to executable file handle */ 0x60 e32_lite e32 /* ??: structure containing exe header */ 0xa8 *o32_lite o32_ptr /* ??: o32 array pointer for exe */ 0xac DWORD pExtPdata /* ??: extend pdata */ 0xb0 BYTE bPrio /* ??: highest priority of all threads of the process */ 0xb1 BYTE fNoDebug /* ??: this process cannot be debugged */ 0xb2 WORD wPad /* padding */ 0xb4 PGPOOL_Q pgqueue /* ??: list of the page owned by the process */ !struct CINFO 0x00 char@4 acName /* 00: object type ID string */ 0x04 BYTE disp /* 04: type of dispatch */ 0x05 BYTE type /* 05: api handle type */ 0x06 WORD cMethods /* 06: # of methods in dispatch table */ 0x08 DWORD ppfnMethods /* 08: ptr to array of methods (in server address space) */ 0x0c DWORD pdwSig /* 0C: ptr to array of method signatures */ 0x10 *PROCESS pServer /* 10: ptr to server process */ !struct HDATA 0x00 DWORD fwd /* 00: links for active handle list */ 0x04 DWORD back 0x08 DWORD hValue /* 08: Current value of handle (nonce) */ 0x0c DWORD lock /* 0C: access information */ 0x10 DWORD ref /* 10: reference information */ 0x14 *CINFO pci /* 14: ptr to object class description structure */ 0x18 DWORD pvObj /* 18: ptr to object */ 0x1c DWORD dwInfo /* 1C: extra handle info */ !struct FFSDinfo 0x00 *FFSDinfo next 0x04 *FFSDinfo prev 0x08 *FFSDinfo pPartition 0x0c *FFSDinfo pFile1 0x10 *FFSDinfo pFile2 0x14 DWORD hProcess 0x18 DWORD hFile 0x1c *GTGTinfo pGtgtInfo // seems to be gtgt struct only in some cases. 0x20 wchar@8 name !struct GTGTinfo 0x00 DWORD magic 0x04 DWORD dw1 0x08 *GDGDinfo pdgdginfo 0x0c *wstr pWStrName 0x10 *GTGTinfo pNext 0x14 *GTGTinfo pPrev 0x18 DWORD dw6 0x1c DWORD dw7 !struct GDGDinfo 0x00 DWORD magic 0x04 *wstr name 0x08 *GTGTinfo pgtgt1 0x0c DWORD dw1 0x10 *GTGTinfo pgtgt2 0x14 DWORD dw2 0x18 DWORD dw3 0x1c DWORD dw4 !struct fsopendev_t 0x00 *fsopendev_t nextptr 0x04 DWORD dwOpenData 0x08 *fsdev_t lpDev 0x0c *DWORD lpdwDevRefCnt 0x10 DWORD dwOpenRefCnt 0x14 DWORD KHandle 0x18 DWORD hProc !struct fsdev_t 0x00 *fsdev_t listnext 0x04 *fsdev_t listprev 0x08 DWORD index 0x0c DWORD dwData 0x10 DWORD dwLoadOrder 0x14 DWORD fnInit 0x18 DWORD fnDeinit 0x1c DWORD fnOpen 0x20 DWORD fnClose 0x24 DWORD fnRead 0x28 DWORD fnWrite 0x2c DWORD fnSeek 0x30 DWORD fnControl 0x34 DWORD fnPowerup 0x38 DWORD fnPowerdn 0x3c DWORD hLib 0x40 DWORD dwId 0x44 DWORD PwrOn 0x48 wchar@3 type 0x4e WORD wFlags 0x50 DWORD dwRefCnt !struct W32Hinfo 0x00 DWORD w0 0x04 *W32Hinfo next 0x08 DWORD w1 0x0c DWORD oid 0x10 *GTGTinfo pgtgt 0x14 DWORD w2 0x18 DWORD w3 0x1c DWORD w4 0x20 DWORD w5 !struct BDEVinfo 0x000 DWORD@11 dw1 0x02c wchar@256 name1 0x22c DWORD@13 dw2 0x260 wchar@28 name2 0x298 DWORD@2 dw3 !struct STRGinfo 0x00 DWORD magic 0x04 *storageinfo pstorageinfo 0x08 *partitioninfo ppartitioninfo 0x0c DWORD@7 dw1 !struct partitioninfo 0x00 DWORD@8 dw !struct storageinfo 0x0000 *somestoragestr somestring 0x0004 DWORD dw1a 0x0008 DWORD bdevhandle 0x000c wchar@16 devname 0x002c wchar@32 desc1 0x006c wchar@32 desc2 0x00ac wchar@260 partdll 0x02b4 wchar@260 profilekey 0x04bc wchar@260 fsname 0x06c4 DWORD@165 dw2 0x0958 wchar@32 desc3 0x0998 DWORD@29 dw3 0x0a0c wchar@260 driverkey 0x0c14 DWORD@11 dw4 !struct somestoragestr 0x00 DWORD codeptr 0x04 wchar@260 str !struct FSMAP 0x00 DWORD hNext; /* Next map in list */ 0x04 DWORD hFile; /* File, or INVALID_HANDLE_VALUE for just vm */ 0x08 DWORD pBase; /* pointer to start of kernel mapped region */ 0x0c DWORD pDirty; /* non-null if r/w real file, points to dirty bitmap */ 0x10 DWORD length; /* length of mapped region */ 0x14 DWORD filelen; /* length of file if hFile != INVALID_HANDLE_VALUE */ 0x18 DWORD reslen; /* length of reservation */ 0x1c *Name name; /* points to name of event */ 0x20 *CLEANEVENT lpmlist; /* List of mappings */ 0x24 DWORD dwDirty; /* Count of dirty pages */ 0x28 BYTE bRestart; /* Has been flushed */ 0x29 BYTE bNoAutoFlush; /* Disallow automatic flushing */ 0x2a BYTE bDirectROM; /* File mapped directly from ROM */ 0x2b BYTE bFlushFlags; /* Flush flags */ 0x2c PGPOOL_Q pgqueue; /* list of the page owned by the mapfile */ !struct PROXY 0x00 DWORD pQPrev; /* Previous proxy for this object queue, must be first for ReQueueByPriority */ 0x04 DWORD pQNext; /* Next proxy for this object queue */ 0x08 DWORD pQUp; 0x0c DWORD pQDown; 0x10 DWORD pThLinkNext; /* Next proxy for this thread */ 0x14 DWORD pObject; /* Pointer to object we're blocked on */ 0x18 BYTE bType; /* Type of object we're blocked on */ 0x19 BYTE prio; /* Current prio we're enqueued on */ 0x1a WORD wCount; /* Count matching thread's wCount */ 0x1c *THREAD pTh; /* Thread "owning" this proxy */ 0x20 DWORD dwRetVal; /* Return value if this is why we wake up */ !struct Module 0x00 *Module lpSelf; /* Self pointer for validation */ 0x04 *Module pMod; /* Next module in chain */ 0x08 *wstr lpszModName; /* Module name */ 0x0c DWORD inuse; /* Bit vector of use */ 0x10 DWORD calledfunc; /* Called entry but not exit */ 0x14 WORD@32 refcnt; /* Reference count per process*/ 0x54 DWORD BasePtr; /* Base pointer of dll load (not 0 based) */ 0x58 DWORD DbgFlags; /* Debug flags */ 0x5c DWORD ZonePtr; /* Debug zone pointer */ 0x60 DWORD startip; /* 0 based entrypoint */ 0x64 openexe_t oe; /* Pointer to executable file handle */ 0x74 e32_lite e32; /* E32 header */ 0xbc *o32_lite o32_ptr; /* O32 chain ptr */ 0xc0 DWORD dwNoNotify; /* 1 bit per process, set if notifications disabled */ 0xc4 WORD wFlags; 0xc6 BYTE bTrustLevel; 0xc7 BYTE bPadding; 0xc8 *Module pmodResource; /* module that contains the resources */ 0xcc DWORD rwLow; /* base address of RW section for ROM DLL */ 0xd0 DWORD rwHigh; /* high address RW section for ROM DLL */ 0xd4 PGPOOL_Q pgqueue; /* list of the page owned by the module */ !struct Name 0x00 WORD wPool 0x02 wchar@260 name !struct MemoryInfo 0x00 DWORD pKData; /* start of kernel's data */ 0x04 DWORD pKEnd; /* end of kernel's data & bss */ 0x08 DWORD cFi; /* # of entries in free memory array */ 0x0c *FreeInfo pFi; /* Pointer to cFi FREEINFO entries */ !struct FreeInfo 0x00 DWORD paStart; /* start of available region */ 0x04 DWORD paEnd; /* end of region (last byte + 1) */ 0x08 DWORD paRealEnd; 0x0c DWORD pUseMap; /* ptr to page usage count map */ !struct MemBlock 0x00 DWORD alk; /* 00: key code for this set of pages */ 0x04 BYTE cUses; /* 04: # of page table entries sharing this leaf */ 0x05 BYTE flags; /* 05: mapping flags */ 0x06 WORD ixBase; /* 06: first block in region */ 0x08 WORD hPf; /* 08: handle to pager */ 0x0a WORD cLocks; /* 0a: lock count */ 0x0c DWORD aPages; /* 0c: entrylo values */ !struct APISET 0x00 CINFO cinfo 0x14 DWORD iReg !struct EVENT 0x00 DWORD hNext; /* Next event in list */ 0x04 *PROXY pProxList; 0x08 *PROXY@32 pProxHash; 0x88 DWORD hPrev; /* previous event in list */ 0x8c BYTE onequeue; 0x8d BYTE state; /* TRUE: signalled, FALSE: unsignalled */ 0x8e BYTE manualreset; /* TRUE: manual reset, FALSE: autoreset */ 0x8f BYTE bMaxPrio; 0x90 *Name name; /* points to name of event */ 0x94 *PROXY pIntrProxy; 0x98 DWORD dwData; /* data associated with the event (CE extention) */ !struct MUTEX 0x00 DWORD hNext; /* Next mutex in list */ 0x04 *PROXY pProxList; 0x08 *PROXY@32 pProxHash; 0x88 DWORD hPrev; /* previous mutex in list */ 0x8c BYTE bListed; 0x8d BYTE bListedPrio; 0x8e WORD LockCount; /* current lock count */ 0x90 DWORD pPrevOwned; /* Prev crit/mutex owned (for prio inversion) */ // was *MUTEX 0x94 DWORD pNextOwned; /* Next crit/mutex owned (for prio inversion) */ // was *MUTEX 0x98 DWORD pUpOwned; // was *MUTEX 0x9c DWORD pDownOwned; // was *MUTEX 0xa0 *THREAD pOwner; /* owner thread */ 0xa4 *Name name; /* points to name of event */ !struct SEMAPHORE 0x00 DWORD hNext; /* Next semaphore in list */ 0x04 *PROXY pProxList; 0x08 *PROXY@32 pProxHash; 0x88 DWORD hPrev; /* previous semaphore in list */ 0x8c DWORD lCount; /* current count */ 0x90 DWORD lMaxCount; /* Maximum count */ 0x94 DWORD lPending; /* Pending count */ 0x98 *Name name; /* points to name of event */ !struct DBInfo 0x00 *DBInfo next 0x04 DWORD hDatabase 0x08 DWORD dw1 0x0c DWORD dw2 0x10 *DBVolume pVolume 0x14 DWORD oid 0x18 DWORD@2 dw4 !struct DBVolume 0x00 *DBVolume next 0x04 DWORD dw1 0x08 DWORD dw2 0x0c DWORD dw3 0x10 wchar@260 path !struct SocketInfo 0x00 DWORD@16 dw !struct CLEANEVENT 0x00 *CLEANEVENT ceptr; 0x04 DWORD base; 0x08 DWORD size; 0x0c DWORD op; !struct CRIT 0x00 *CRITICAL_SECTION lpcs; /* Pointer to critical_section structure */ 0x04 *PROXY pProxList; 0x08 *PROXY@32 pProxHash; 0x88 *CRIT pPrev; /* previous event in list */ 0x8c BYTE bListed; /* Is this on someone's owner list */ 0x8d BYTE bListedPrio; 0x8e BYTE iOwnerProc; /* Index of owner process */ 0x8f BYTE bPad; 0x90 DWORD pPrevOwned; /* Prev crit/mutex (for prio inversion) */ // was *CRIT 0x94 DWORD pNextOwned; /* Next crit/mutex section owned (for prio inversion) */ // was *CRIT 0x98 DWORD pUpOwned; // was *CRIT 0x9c DWORD pDownOwned; // was *CRIT 0xa0 *CRIT pNext; /* Next CRIT in list */ !struct CRITICAL_SECTION 0x00 DWORD LockCount; /* Nesting count on critical section */ 0x04 DWORD OwnerThread; /* Handle of owner thread */ 0x08 DWORD hCrit; /* Handle to this critical section */ 0x0c DWORD needtrap; /* Trap in when freeing critical section */ 0x10 DWORD dwContentions; /* Count of contentions */ !struct DWLIST 0x00 DWORD@8 dw !struct ROMHDR 0x00 DWORD dllFirst 0x04 DWORD dllLast 0x08 DWORD physStart 0x0C DWORD physLast 0x10 DWORD nummods 0x14 DWORD ulRAMStart 0x18 DWORD ulRAMFree 0x1C DWORD ulRAMEnd 0x20 DWORD ulCopyEntries 0x24 DWORD ulCopyOffset 0x28 DWORD ulProfileLe 0x2C DWORD ulProfileOffset 0x30 DWORD numfiles 0x34 DWORD ulKernelFlags 0x38 DWORD ulFSRamPercent 0x3C DWORD ulDrivglobStart 0x40 DWORD ulDrivglobLen 0x44 WORD usCPUType 0x46 WORD usMiscFlags 0x48 DWORD pExtensions 0x4C DWORD ulTrackingStart 0x50 DWORD ulTrackingLen !struct COPYentry 0x00 DWORD ulSource 0x04 DWORD ulDest 0x08 DWORD ulCopyLen 0x0C DWORD ulDestLen !struct FILESentry 0x00 DWORD dwFileAttributes 0x04 FILETIME ftTime 0x0C DWORD nRealFileSize 0x10 DWORD nCompFileSize 0x14 *wstr lpszFileName 0x18 DWORD ulLoadOffset !struct TOCentry 0x00 DWORD dwFileAttributes 0x04 FILETIME ftTime 0x0C DWORD nFileSize 0x10 *wstr lpszFileName 0x14 DWORD ulE32Offset 0x18 DWORD ulO32Offset 0x1C DWORD ulLoadOffset !struct e32_rom 0x00 WORD e32_objcnt 0x02 WORD e32_imageflags 0x04 DWORD e32_entryrva 0x08 DWORD e32_vbase 0x0C WORD e32_subsysmajor 0x0E WORD e32_subsysminor 0x10 DWORD e32_stackmax 0x14 DWORD e32_vsize 0x18 DWORD e32_sect14rva 0x1C DWORD e32_sect14size 0x20 info@9 e32_unit 0x68 DWORD e32_subsys !struct o32_rom 0x00 DWORD o32_vsize 0x04 DWORD o32_rva 0x08 DWORD o32_psize 0x0C DWORD o32_dataptr 0x10 DWORD o32_realaddr 0x14 DWORD o32_flags !struct IMAGE_DEBUG_DIRECTORY 0x00 DWORD Characteristics 0x04 DWORD TimeDateStamp 0x08 WORD MajorVersion 0x0A WORD MinorVersion 0x0C DWORD Type 0x10 DWORD SizeOfData 0x14 DWORD AddressOfRawData 0x18 DWORD PointerToRawData !struct IMAGE_DOS_HEADER 0x00 WORD e_magic /* Magic number */ 0x02 WORD e_cblp /* Bytes on last page of file */ 0x04 WORD e_cp /* Pages in file */ 0x06 WORD e_crlc /* Relocations */ 0x08 WORD e_cparhdr /* Size of header in paragraphs */ 0x0a WORD e_minalloc /* Minimum extra paragraphs needed */ 0x0c WORD e_maxalloc /* Maximum extra paragraphs needed */ 0x0e WORD e_ss /* Initial (relative) SS value */ 0x10 WORD e_sp /* Initial SP value */ 0x12 WORD e_csum /* Checksum */ 0x14 WORD e_ip /* Initial IP value */ 0x16 WORD e_cs /* Initial (relative) CS value */ 0x18 WORD e_lfarlc /* File address of relocation table */ 0x1a WORD e_ovno /* Overlay number */ 0x1c WORD@4 e_res /* Reserved words */ 0x24 WORD e_oemid /* OEM identifier (for e_oeminfo) */ 0x26 WORD e_oeminfo /* OEM information; e_oemid specific */ 0x28 WORD@10 e_res2 /* Reserved words */ 0x3c DWORD e_lfanew /* File address of new exe header */ !struct e32_exe 0x00 char@4 e32_magic /* Magic number E32_MAGIC */ 0x04 WORD e32_cpu /* The CPU type */ 0x06 WORD e32_objcnt /* Number of memory objects */ 0x08 DWORD e32_timestamp /* Time EXE file was created/modified */ 0x0c DWORD e32_symtaboff /* Offset to the symbol table */ 0x10 DWORD e32_symcount /* Number of symbols */ 0x14 WORD e32_opthdrsize /* Optional header size */ 0x16 WORD e32_imageflags /* Image flags */ 0x18 WORD e32_coffmagic /* Coff magic number (usually 0x10b) */ 0x1a BYTE e32_linkmajor /* The linker major version number */ 0x1b BYTE e32_linkminor /* The linker minor version number */ 0x1c DWORD e32_codesize /* Sum of sizes of all code sections */ 0x20 DWORD e32_initdsize /* Sum of all initialized data size */ 0x24 DWORD e32_uninitdsize /* Sum of all uninitialized data size */ 0x28 DWORD e32_entryrva /* Relative virt. addr. of entry point */ 0x2c DWORD e32_codebase /* Address of beginning of code section*/ 0x30 DWORD e32_database /* Address of beginning of data section*/ 0x34 DWORD e32_vbase /* Virtual base address of module */ 0x38 DWORD e32_objalign /* Object Virtual Address align. factor*/ 0x3c DWORD e32_filealign /* Image page alignment/truncate factor*/ 0x40 WORD e32_osmajor /* The operating system major ver. no. */ 0x42 WORD e32_osminor /* The operating system minor ver. no. */ 0x44 WORD e32_usermajor /* The user major version number */ 0x46 WORD e32_userminor /* The user minor version number */ 0x48 WORD e32_subsysmajor /* The subsystem major version number */ 0x4a WORD e32_subsysminor /* The subsystem minor version number */ 0x4c DWORD e32_res1 /* Reserved bytes - must be 0 */ 0x50 DWORD e32_vsize /* Virtual size of the entire image */ 0x54 DWORD e32_hdrsize /* Header information size */ 0x58 DWORD e32_filechksum /* Checksum for entire file */ 0x5c WORD e32_subsys /* The subsystem type */ 0x5e WORD e32_dllflags /* DLL flags */ 0x60 DWORD e32_stackmax /* Maximum stack size */ 0x64 DWORD e32_stackinit /* Initial committed stack size */ 0x68 DWORD e32_heapmax /* Maximum heap size */ 0x6c DWORD e32_heapinit /* Initial committed heap size */ 0x70 DWORD e32_res2 /* Reserved bytes - must be 0 */ 0x74 DWORD e32_hdrextra /* Number of extra info units in header*/ 0x78 info@16 e32_unit /* Array of extra info units */ !struct o32_obj 0x00 char@8 o32_name; /* Object name */ 0x08 DWORD o32_vsize; /* Virtual memory size */ 0x0c DWORD o32_rva; /* Object relative virtual address */ 0x10 DWORD o32_psize; /* Physical file size of init. data */ 0x14 DWORD o32_dataptr; /* Image pages offset */ 0x18 DWORD o32_realaddr; /* pointer to actual */ 0x1c DWORD o32_access; /* assigned access */ 0x20 DWORD o32_temp3; 0x24 DWORD o32_flags; /* Attribute flags for the object */