rizin/test/db/cmd/cmd_pf
NOT XVilka 1a0c5c655a
librz/type: fix orphan '*' when emitting pf format for typedef'd void*/char* (#6420)
When type_to_format / type_to_format_pair encounter a pointer field whose
pointee is reachable only through a typedef chain that ends at the
atomic 'void' or 'char' (e.g. PVOID -> VOID -> void, LPSTR -> CHAR ->
char, HANDLE -> ... -> void in some platform headers), they emit a bare
'*' and recurse into the pointee.  The recursion produces nothing for
'void' (no format) and emits the legacy 'c' for 'char', so the
generated pf string ends up with either an orphan trailing/internal '*'
or the sequence '*c', which the new pf parser introduced in the
recent rewrite rejects: it requires '*' to be followed by a complete
dereferenceable spec ('z', a sized integer like 'd4'/'x2'/'u8', or
'?').  The result is parser warnings and dropped fields during 'tp':

  rizin -k windows -c 'tp _OBJECT_ATTRIBUTES'
    WARNING: pf: unknown specifier '*' at position 4, skipping
    WARNING: pf: unknown specifier '*' at position 4, skipping
    [only 4 of 6 fields rendered]

  rizin -k windows -c 'tp _SYSTEM_INFO'
    [11 fields collapse to 4]

  rizin -k windows -c 'tp _STARTUPINFOA'
    [three LPSTR fields render as '*c' which the parser cannot
     usefully follow]

The top-level rz_type_as_format() already special-cases 'void *',
'char *', and callable pointers, mapping them to 'p' and 'z'.  But the
inner walkers do not, because rz_type_is_void_ptr / rz_type_is_char_ptr
compare the literal identifier name and so do not see through typedefs
like VOID->void or CHAR->char.

Fix it by adding ptr_pointee_resolves_to(), a small static helper in
format.c that walks the typedb to find the canonical atomic name for
the pointee (bounded depth so a circular typedef cannot send the
resolver into an infinite loop), and using it in both POINTER branches
before the '*'+recurse fallback.  Pointers whose pointee resolves to
'void' (or a void-aliased typedef) now emit 'p'; pointers whose pointee
resolves to 'char' (or a char-aliased typedef) emit 'z'.  Everything
else continues to emit '*<inner>' unchanged, so single-level
LPBYTE -> BYTE -> unsigned char still renders as the perfectly valid
'*x1', and pointer-to-struct '*?' chains are untouched.

After the fix, the same upstream structs produce well-formed pf
strings:

  ts _OBJECT_ATTRIBUTES   -> 'x8p**x1x8pp ...'         (two PVOID -> pp)
  ts _SYSTEM_INFO          -> 'x2x2d4ppx8d4d4d4x2x2 ...' (two LPVOID -> pp)
  ts _STARTUPINFOA         -> 'd4zzzd4...*x1ppp ...'   (three LPSTR -> zzz;
                                                       LPBYTE still '*x1')

Add a regression test in test/db/cmd/cmd_pf that exercises both shapes
via 'ts _SECURITY_ATTRIBUTES' (single LPVOID) and 'ts _STARTUPINFOA'
(three LPSTR + one LPBYTE).  Without this commit the test catches the
bug -- the LPVOID field becomes orphan '*' inside the format and the
LPSTR fields render as '*c'; with the commit both render cleanly as
documented above.

Also update one existing EXPECT in test/db/cmd/types: the 'td with
comments' test had encoded the legacy 'pf "d4[5]*c b foo"' shape for
'char *foo[5]'.  With the fix this becomes 'pf "d4[5]z b foo"', which
is both well-formed under the new DSL and a more accurate description
(an array of zstrings rather than an array of pointers to a single
char).

Co-authored-by: Anton Kochkov <anton.kockov@gmail.com>
2026-05-29 09:06:28 +08:00

1081 lines
23 KiB
Text

NAME=pf QQ
FILE==
CMDS=<<EOF
e asm.arch=arm
e cfg.bigendian=false
b 256
woe 0 255 0x11
pf Q
pf QQ
pfq QQ
EOF
EXPECT=<<EOF
0x00000000 = 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
0x00000000 = 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
0x00000010 = 10 21 32 43 54 65 76 87 98 a9 ba cb dc ed fe 0f
00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
10 21 32 43 54 65 76 87 98 a9 ba cb dc ed fe 0f
EOF
RUN
NAME=pf.-x
FILE==
CMDS=<<EOF
pfn foo xxd
pfn~foo
pf- foo
pfn~foo
EOF
EXPECT=<<EOF
foo "xxd"
EOF
RUN
NAME=pf-*
FILE==
CMDS=<<EOF
pfn foo xxd
pfn~foo
pf-*
pfn~foo
EOF
EXPECT=<<EOF
foo "xxd"
EOF
RUN
NAME=pf i foo @x:0x01
FILE==
ARGS=-a x86 -b 32
CMDS=pf i foo @x:0x01
EXPECT=<<EOF
0x00000000 : foo = 1 [LE]
EOF
RUN
NAME=pf [3]ub
FILE==
CMDS=pf [3]ub
EXPECT=<<EOF
0x00000000 = [ 0, 0, 0 ] [LE]
0x0000000c = 0b0000_0000 [LE]
EOF
RUN
NAME=Cf main
FILE==
CMDS=Cf main;C*
EXPECT=
RUN
NAME=Cf 1 n2
FILE==
CMDS=Cf 1 n2;C
EXPECT=<<EOF
0x00000000 format 1 n2
EOF
RUN
NAME=seteq
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
pfn foo "x4x4d4 foo bar cow"
w hello happy world
w goodbye cruel world @ 0x20
s 0x20
pf. foo @ 0x00
pfa foo
EOF
EXPECT=<<EOF
0x00000000 : foo = 0x6c6c6568 [LE]
0x00000004 : bar = 0x6168206f [LE]
0x00000008 : cow = 544829552 [LE]
0x00000020 : foo = 0x646f6f67 [LE]
0x00000024 : bar = 0x20657962 [LE]
0x00000028 : cow = 1702195811 [LE]
EOF
RUN
NAME=float
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=arm
e cfg.bigendian=false
wx 00007a45457a0000
e cfg.bigendian=false
pf ff
wx 00007a45457a0000
e cfg.bigendian=true
pf ff
EOF
EXPECT=<<EOF
0x00000000 = 4000 [LE]
0x00000004 = 4.38620432e-41 [LE]
0x00000000 = 4000 [LE]
0x00000004 = 4.38620432e-41 [LE]
EOF
RUN
NAME=seteq2
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
pfn foo "x4d4 foo bar"
pf. foo
EOF
EXPECT=<<EOF
0x00000000 : foo = 0x00000000 [LE]
0x00000004 : bar = 0 [LE]
EOF
RUN
NAME=types
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx 00007a452a4b9a0200002a
pf fcb1d4C foo bar fool beer plop
EOF
EXPECT=<<EOF
0x00000000 : foo = 4000 [LE]
0x00000004 : bar = '*'
0x00000005 : fool = 0b0100_1011 [LE]
0x00000006 : beer = 666 [LE]
0x0000000a : plop = 42 [LE]
EOF
RUN
NAME=word types
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx efbeadde002a0000adde
pf x8x2 bigWord beef
EOF
EXPECT=<<EOF
0x00000000 : bigWord = 0x00002a00deadbeef [LE]
0x00000008 : beef = 0xdead [LE]
EOF
RUN
NAME=Register
# The legacy 'r (regname)' form looked up a CPU register by name and
# printed its value (via RzPrint::get_register). The new parser
# repurposes 'r' as "raw hex byte dump", so the register-fetch path
# is gone -- the test is kept as BROKEN with this comment so the
# regression is tracked. Restoring would mean wiring a new
# register-lookup hook through RzPfCtx, which is outside the scope of
# the parser rewrite.
BROKEN=1
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
e asm.arch=x86
e analysis.arch=x86
ar eax=4000
ar eip=42
pfn plop "rr (eax)reg1 (eip)reg2"
pf. plop
pf.j plop
EOF
EXPECT=<<EOF
reg1 : eax : 0x00000fa0
reg2 : eip : 0x0000002a
[{"name":"reg1","type":"r","offset":0,"value":4000},{"name":"reg2","type":"r","offset":0,"value":42}]
EOF
RUN
NAME=Pointers
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx 30
wx 20 @ 0x04
wx 40 @ 0x08
wx 2a @ 0x20
w TROLL @ 0x30
wx a00f @ 0x40
e asm.bits=32 # pointer size
pfn plop *z*d4*x2 nb name blob
pf. plop
EOF
EXPECT=<<EOF
0x00000000 : nb = (*0x30) "TROLL"
0x00000004 : name = (*0x20) 42
0x00000008 : blob = (*0x40) 0x0fa0
EOF
RUN
NAME=Pointer sizes
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx added0dec0de5eba7ada1eab11caefbeadde0bb0
pf p2p4p8pp2
EOF
EXPECT=<<EOF
0x00000000 = 0xdead
0x00000002 = 0xdec0ded0
0x00000006 = 0xca11ab1eda7aba5e
0x0000000e = 0xdeadbeef
0x00000012 = 0xb00b
EOF
RUN
NAME=swap endianess
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx deadbeef00000000adde
pf X8X2 bigWord beef
EOF
EXPECT=<<EOF
0x00000000 : bigWord = 0xdeadbeef00000000 [BE]
0x00000008 : beef = 0xadde [BE]
EOF
RUN
NAME=String pointer
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
w TROLL @ 0x30
wx 30
wx a00f @ 0x04
e asm.bits=32
pf *zd4 Pouet Plop
EOF
EXPECT=<<EOF
0x00000000 : Pouet = (*0x30) "TROLL"
0x00000004 : Plop = 4000 [LE]
EOF
RUN
NAME=pf format from typedef'd void* / char* (orphan-* regression)
FILE==
ARGS=-a x86 -b 64 -k windows
CMDS=<<EOF
ts _SECURITY_ATTRIBUTES
ts _STARTUPINFOA
EOF
EXPECT=<<EOF
pf "d4pd4 nLength (LPVOID)lpSecurityDescriptor bInheritHandle"
pf "d4*c*c*cd4d4d4d4d4d4d4d4x2x2*x1ppp cb (LPSTR)lpReserved (LPSTR)lpDesktop (LPSTR)lpTitle dwX dwY dwXSize dwYSize dwXCountChars dwYCountChars dwFillAttribute dwFlags wShowWindow cbReserved2 (LPBYTE)lpReserved2 hStdInput hStdOutput hStdError"
EOF
RUN
NAME=timestamp
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx 321ED92D90DF5254
pf tt troll plop
EOF
EXPECT=<<EOF
0x00000000 : troll = [unix32] [LE] 1994-05-17 19:42:42 UTC
0x00000004 : plop = [unix32] [LE] 2014-10-31 01:02:08 UTC
EOF
RUN
NAME=named obj
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx a00f00004b
pfn troll "d4c lol cat"
pf. troll
EOF
EXPECT=<<EOF
0x00000000 : lol = 4000 [LE]
0x00000004 : cat = 'K'
EOF
RUN
NAME=array obj
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx a00f00004b2a0000004c
pfn troll "2d4c nb plop"
pf. troll
EOF
EXPECT=<<EOF
0x00000000 : nb = 4000 [LE]
0x00000004 : plop = 'K'
0x00000005 : nb = 42 [LE]
0x00000009 : plop = 'L'
EOF
RUN
NAME=write test
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx 32000000424c41424c41424c41424c41
pfn troll "d4zd4 hu swagg plop"
pfw troll.hu 42
pfw troll.swagg "B*A AA"
pfw troll.plop 4000
pf. troll
EOF
EXPECT=<<EOF
hu : 0x00000000 = 42
swagg : 0x00000004 = "B*A AABLABLA"
plop : 0x00000011 = 4000
0x00000000 : hu = 42 [LE]
0x00000004 : swagg = "B*A AABLABLA"
0x00000011 : plop = 4000 [LE]
EOF
RUN
NAME=write wide string
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx 42004c00410042004c00410042004c00410042004c0041000000a00f0000
pfn troll "Zd4 swagg plop"
pf. troll
pfw troll.swagg "BWA AA"
pfw troll.plop "42"
pf. troll
EOF
EXPECT=<<EOF
0x00000000 : swagg = "BLABLABLABLA"
0x0000001a : plop = 4000 [LE]
swagg : 0x00000000 = "BWA AABLABLA"
plop : 0x0000001a = 42
0x00000000 : swagg = "BWA AABLABLA"
0x0000001a : plop = 42 [LE]
EOF
RUN
NAME=fixed size variable
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx a00f0000000000002a412f00007a4500000000402a44adde00000000efbeadde00000000000000000000000040
pf [2]d4[3]b1[2]f4[3]c[3]x2[2]x8[6]x4
EOF
EXPECT=<<EOF
0x00000000 = [ 4000, 0 ] [LE]
0x00000008 = [ 0b0010_1010, 0b0100_0001, 0b0010_1111 ] [LE]
0x0000000b = [ 4000, 0 ] [LE]
0x00000013 = [ '@', '*', 'D' ]
0x00000016 = [ 0xdead, 0x0000, 0x0000 ] [LE]
0x0000001c = [ 0x00000000deadbeef, 0x0000000000000000 ] [LE]
0x0000002c = [ 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 ] [LE]
EOF
RUN
NAME=fixed size str, widechar, and var
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
w TROLL
wx 12 @ 0x02
wx a00f @ 0x0a
ww PLOP @ 0x16
wx 2a @ 0x2a
pf [10]z[3]d4[10]Zb1
EOF
EXPECT=<<EOF
0x00000000 = "TR\x12LL"
0x0000000a = [ 4000, 0, 0 ] [LE]
0x00000016 = "PLOP"
0x00000020 = 0b0000_0000 [LE]
EOF
RUN
NAME=Enum test
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
td enum troll { BITE=42, PATE=4000};
wx a00f
pf E (troll)plop
EOF
EXPECT=<<EOF
0x00000000 : plop = 0x00000fa0 ; PATE
EOF
RUN
NAME=32 bit twice then string
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wv 0x10
wv 0x10 @ 4
w hello @ 0x10
pf ss
pf *x4*x4
pf *z*z
EOF
EXPECT=<<EOF
0x00000000 = (*0x10) "hello"
0x00000004 = (*0x10) "hello"
0x00000000 = (*0x10) 0x6c6c6568
0x00000004 = (*0x10) 0x6c6c6568
0x00000000 = (*0x10) "hello"
0x00000004 = (*0x10) "hello"
EOF
RUN
NAME=simple union test
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wv 0x2a
pf 0iw integer word
EOF
EXPECT=<<EOF
0x00000000 : integer = 42 [LE]
0x00000000 : word = 0x002a [LE]
EOF
RUN
NAME=simple nested struct
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 2a
wx a00f @ 0x04
wx 2a @ 0x08
wx 10 @ 0x0a
wx efbe @ 0x0e
wx 20 @ 0x10
pfn troll "d4x2 integer word"
pfn plop "d4??d4 firstInt (troll)One (troll)Two secondInt"
pf. plop
EOF
EXPECT=<<EOF
0x00000000 : firstInt = 42 [LE]
0x00000004 : One = struct<troll> {
0x00000004 : integer = 4000 [LE]
0x00000008 : word = 0x002a [LE]
}
0x0000000a : Two = struct<troll> {
0x0000000a : integer = 16 [LE]
0x0000000e : word = 0xbeef [LE]
}
0x00000010 : secondInt = 32 [LE]
EOF
RUN
NAME=nested struct
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 2a000000a00f00001234100000006416
wx 2a0000002a @ 0x10
pfn troll "d4x2*? integer word (troll)Bah"
pfn plop "d4?x2 firstInt (troll)Boh plop"
pf. plop
EOF
EXPECT=<<EOF
0x00000000 : firstInt = 42 [LE]
0x00000004 : Boh = struct<troll> {
0x00000004 : integer = 4000 [LE]
0x00000008 : word = 0x3412 [LE]
0x0000000a : Bah = (*0x10) struct<troll> {
0x00000010 : integer = 42 [LE]
0x00000014 : word = 0x002a [LE]
0x00000016 : Bah = (*0x0)
}
}
0x0000000e : plop = 0x1664 [LE]
EOF
RUN
NAME=nested unions
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 2a000000a00f0000a02000000172
pfn struct "x4x4 first second"
pfn union "0d4?x2 integer (struct)swagg word"
pfn plop "d4?x2 firstInt (union)Boh plop"
pf. plop
EOF
EXPECT=<<EOF
0x00000000 : firstInt = 42 [LE]
0x00000004 : Boh = struct<union> {
0x00000004 : integer = 4000 [LE]
0x00000004 : swagg = struct<struct> {
0x00000004 : first = 0x00000fa0 [LE]
0x00000008 : second = 0x000020a0 [LE]
}
0x00000004 : word = 0x0fa0 [LE]
}
0x0000000c : plop = 0x7201 [LE]
EOF
RUN
NAME=complex nested struct
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 341289679a020000a00f00002a003000000014426416
wx 800600000040 @ 0x20
wx 14000000641620000000 @ 0x30
pfn troll "d4x2*? integer word (troll)Bah"
pfn plop "d4?x2 first (troll)Boh bwa"
pfn gobelin "x2x2?x4 blah meh (plop)Buh foo"
pf. gobelin
EOF
EXPECT=<<EOF
0x00000000 : blah = 0x1234 [LE]
0x00000002 : meh = 0x6789 [LE]
0x00000004 : Buh = struct<plop> {
0x00000004 : first = 666 [LE]
0x00000008 : Boh = struct<troll> {
0x00000008 : integer = 4000 [LE]
0x0000000c : word = 0x002a [LE]
0x0000000e : Bah = (*0x30) struct<troll> {
0x00000030 : integer = 20 [LE]
0x00000034 : word = 0x1664 [LE]
0x00000036 : Bah = (*0x20) struct<troll> {
0x00000020 : integer = 1664 [LE]
0x00000024 : word = 0x4000 [LE]
0x00000026 : Bah = (*0x0)
}
}
}
0x00000012 : bwa = 0x4214 [LE]
}
0x00000014 : foo = 0x00001664 [LE]
EOF
RUN
NAME=flag for nested struct
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 341289679a020000a00f00002a00300000001442
wx 800600000040 @ 0x20
wx 14000000641620000000 @ 0x30
pfn troll "d4x2*? integer word (troll)Bah"
pfn plop "d4?x2 first (troll)Boh bwa"
pfn gobelin "x2x2? blah meh (plop)Buh"
pf. gobelin
EOF
EXPECT=<<EOF
0x00000000 : blah = 0x1234 [LE]
0x00000002 : meh = 0x6789 [LE]
0x00000004 : Buh = struct<plop> {
0x00000004 : first = 666 [LE]
0x00000008 : Boh = struct<troll> {
0x00000008 : integer = 4000 [LE]
0x0000000c : word = 0x002a [LE]
0x0000000e : Bah = (*0x30) struct<troll> {
0x00000030 : integer = 20 [LE]
0x00000034 : word = 0x1664 [LE]
0x00000036 : Bah = (*0x20) struct<troll> {
0x00000020 : integer = 1664 [LE]
0x00000024 : word = 0x4000 [LE]
0x00000026 : Bah = (*0x0)
}
}
}
0x00000012 : bwa = 0x4214 [LE]
}
EOF
RUN
NAME=struct size
FILE=malloc://256
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
pfn plop "x2d4 word int"
pfn troll "x1cd4x2x8fd4o4x4s:S.[4]z[2]B[4]E? byte char int word quad float hexa octal hex strp wstrp str bitfield enum (plop)struct"
pfs troll
EOF
EXPECT=<<EOF
50
EOF
RUN
NAME=Print value only
FILE=bins/pe/ch22.exe
ARGS=-nn
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
s 0x80
pfv .pe_nt_image_headers32.optionalHeader.dataDirectory[5].virtualAddress
EOF
EXPECT=<<EOF
0x0000c000
EOF
RUN
NAME=print signed and unsigned values
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wx 71776572747975696f706173646667686a6b6c7a786376626e6d71776572747975696f706173646667686a6b6c7a786376626e6d
pf U8..U4.U2:U1..u8..u4u2u1 a b c d e f
EOF
EXPECT=<<EOF
0x00000000 : a = 8176115190769218921 [BE]
0x0000000a : b = 1634952294 [BE]
0x0000000f : c = 26730 [BE]
0x00000011 : d = 0x6b
0x00000012 : e = 108 [BE]
0x00000015 : f = 7311437234876610147 [LE]
0x0000001f = 1869182329 [LE]
0x00000023 = 24944 [LE]
0x00000025 = 115 [LE]
EOF
RUN
NAME=Combining flags, backtick, and var length array
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
f test 4 @ 0x20
w SWAG
wx 04 @ test
wx 20 @ 0x4
pfn plop "d4p int ptr"
pf [`pfv p @ test`]c
pf [*`pfv .plop.ptr`]c
EOF
EXPECT=<<EOF
0x00000000 = 'S'
0x00000000 = 'S'
EOF
RUN
NAME=print n-times a format
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
wx 71776572747975696f706173646667686a6b6c7a786376626e6d71776572747975696f706173646667686a6b6c7a786376626e6d
pfn plop "d4p int ptr"
pf {2}? (plop)structname @ 0
EOF
EXPECT=<<EOF
0x00000000 : structname = struct<plop> {
0x00000000 : int = 1919252337 [LE]
0x00000004 : ptr = 0x7361706f69757974
}
0x0000000c : structname = struct<plop> {
0x0000000c : int = 1751606884 [LE]
0x00000010 : ptr = 0x627663787a6c6b6a
}
EOF
RUN
NAME=print with byte(s) skip
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
wx 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
pfn abc "d4c...d4:pd4d4 a b c d e f"
pf. abc
EOF
EXPECT=<<EOF
0x00000000 : a = 50462976 [LE]
0x00000004 : b = '.'
0x00000008 : c = 185207048 [LE]
0x0000000c : d = 0x0c
0x0000000d : e = 0x14131211100f0e0d
0x00000015 : f = 404166165 [LE]
0x00000019 = 471538201 [LE]
EOF
RUN
NAME=PE test
FILE=bins/pe/ch22.exe
ARGS=-nn
CMDS=<<EOF
e asm.arch=x86
s 0x80
pf. pe_nt_image_headers32
EOF
EXPECT=<<EOF
0x00000080 : signature = "PE"
0x00000084 : fileHeader = struct<pe_image_file_header> {
0x00000084 : machine = 0x0000014c ; IMAGE_FILE_MACHINE_I386
0x00000086 : numberOfSections = 0x0004 [LE]
0x00000088 : timeDateStamp = [unix32] [LE] 2014-09-11 18:21:46 UTC
0x0000008c : pointerToSymbolTable = 0x00000000 [LE]
0x00000090 : numberOfSymbols = 0x00000000 [LE]
0x00000094 : sizeOfOptionalHeader = 0x00e0 [LE]
0x00000096 : characteristics = 0x00000102 : IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE
}
0x00000098 : optionalHeader = struct<pe_image_optional_header32> {
0x00000098 : magic = 0x0000010b ; IMAGE_NT_OPTIONAL_HDR32_MAGIC
0x0000009a : majorLinkerVersion = 0x0b [LE]
0x0000009b : minorLinkerVersion = 0x00 [LE]
0x0000009c : sizeOfCode = 0x00003000 [LE]
0x000000a0 : sizeOfInitializedData = 0x00003400 [LE]
0x000000a4 : sizeOfUninitializedData = 0x00000000 [LE]
0x000000a8 : addressOfEntryPoint = 0x00004f3e [LE]
0x000000ac : baseOfCode = 0x00002000 [LE]
0x000000b0 : baseOfData = 0x00006000 [LE]
0x000000b4 : imageBase = 0x00400000 [LE]
0x000000b8 : sectionAlignment = 0x00002000 [LE]
0x000000bc : fileAlignment = 0x00000200 [LE]
0x000000c0 : majorOperatingSystemVersion = 0x0004 [LE]
0x000000c2 : minorOperatingSystemVersion = 0x0000 [LE]
0x000000c4 : majorImageVersion = 0x0000 [LE]
0x000000c6 : minorImageVersion = 0x0000 [LE]
0x000000c8 : majorSubsystemVersion = 0x0006 [LE]
0x000000ca : minorSubsystemVersion = 0x0000 [LE]
0x000000cc : win32VersionValue = 0x00000000 [LE]
0x000000d0 : sizeOfImage = 0x0000e000 [LE]
0x000000d4 : sizeOfHeaders = 0x00000400 [LE]
0x000000d8 : checkSum = 0x00000000 [LE]
0x000000dc : subsystem = 0x00000002 ; IMAGE_SUBSYSTEM_WINDOWS_GUI
0x000000de : dllCharacteristics = 0x00008560 : IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_NO_SEH | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
0x000000e0 : sizeOfStackReserve = 0x00100000 [LE]
0x000000e4 : sizeOfStackCommit = 0x00001000 [LE]
0x000000e8 : sizeOfHeapReserve = 0x00100000 [LE]
0x000000ec : sizeOfHeapCommit = 0x00001000 [LE]
0x000000f0 : loaderFlags = 0x00000000 [LE]
0x000000f4 : numberOfRvaAndSizes = 0x00000010 [LE]
0x000000f8 : dataDirectory = struct<pe_image_data_directory> {
0x000000f8 : virtualAddress = 0x00000000 [LE]
0x000000fc : size = 0x00000000 [LE]
0x00000100 : virtualAddress = 0x00004ef0 [LE]
0x00000104 : size = 0x0000004b [LE]
0x00000108 : virtualAddress = 0x00008000 [LE]
0x0000010c : size = 0x00002e40 [LE]
0x00000110 : virtualAddress = 0x00000000 [LE]
0x00000114 : size = 0x00000000 [LE]
0x00000118 : virtualAddress = 0x00000000 [LE]
0x0000011c : size = 0x00000000 [LE]
0x00000120 : virtualAddress = 0x0000c000 [LE]
0x00000124 : size = 0x0000000c [LE]
0x00000128 : virtualAddress = 0x00006000 [LE]
0x0000012c : size = 0x0000001c [LE]
0x00000130 : virtualAddress = 0x00000000 [LE]
0x00000134 : size = 0x00000000 [LE]
0x00000138 : virtualAddress = 0x00000000 [LE]
0x0000013c : size = 0x00000000 [LE]
0x00000140 : virtualAddress = 0x00000000 [LE]
0x00000144 : size = 0x00000000 [LE]
0x00000148 : virtualAddress = 0x00000000 [LE]
0x0000014c : size = 0x00000000 [LE]
0x00000150 : virtualAddress = 0x00000000 [LE]
0x00000154 : size = 0x00000000 [LE]
0x00000158 : virtualAddress = 0x00002000 [LE]
0x0000015c : size = 0x00000008 [LE]
0x00000160 : virtualAddress = 0x00000000 [LE]
0x00000164 : size = 0x00000000 [LE]
0x00000168 : virtualAddress = 0x00002008 [LE]
0x0000016c : size = 0x00000048 [LE]
0x00000170 : virtualAddress = 0x00000000 [LE]
0x00000174 : size = 0x00000000 [LE]
}
}
EOF
RUN
NAME=Variable length array
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 2a @ 0x20
pf [*0x20]c
pf [(42-21-11)/2]c
EOF
EXPECT=<<EOF
0x00000000 = '.'
0x00000000 = '.'
EOF
RUN
NAME=Infinite Recursion segfault 1
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
pfn _NT_TIB "? (_NT_TIB)Self"
pf. _NT_TIB > /dev/null
pfn~NT_TIB
EOF
EXPECT=<<EOF
_NT_TIB "? (_NT_TIB)Self"
EOF
RUN
NAME=Infinite Recursion segfault 2
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
pfn _NT_TIB "pppppd4p? ExceptionList StackBase StackLimit SubSystemTib FiberData Version ArbitraryUserPointer (_NT_TIB)Self"
pf. _NT_TIB > /dev/null
pfn~NT_TIB
EOF
EXPECT=<<EOF
_NT_TIB "pppppd4p? ExceptionList StackBase StackLimit SubSystemTib FiberData Version ArbitraryUserPointer (_NT_TIB)Self"
EOF
RUN
NAME=One byte enum endianness
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=arm
e cfg.bigendian=true
wb 4142434431323334
td "enum ascii{ LETTER_A=0x41, LETTER_D=0x44, DIGIT_1=0x31, DIGIT_4=0x34}"
pfn somestring "[1]E[1]E[1]E[1]E[1]E[1]E[1]E[1]E (ascii)B1 (ascii)B2 (ascii)B3 (ascii)B4 (ascii)B5 (ascii)B6 (ascii)B7 (ascii)B8"
pf. somestring
EOF
EXPECT=<<EOF
0x00000000 : B1 = 0x00000041 ; LETTER_A
0x00000001 : B2 = 0x00000042
0x00000002 : B3 = 0x00000043
0x00000003 : B4 = 0x00000044 ; LETTER_D
0x00000004 : B5 = 0x00000031 ; DIGIT_1
0x00000005 : B6 = 0x00000032
0x00000006 : B7 = 0x00000033
0x00000007 : B8 = 0x00000034 ; DIGIT_4
EOF
RUN
NAME=union pf
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
wv4 1234
pf "d4;d4"
pf "d4,,,,d4"
EOF
EXPECT=<<EOF
0x00000000 = 1234 [LE]
0x00000004 = 0 [LE]
0x00000000 = 1234 [LE]
0x00000004 = 0 [LE]
EOF
RUN
NAME=pf
FILE=bins/elf/crackme0x05
CMDS=pf 2F
EXPECT=<<EOF
0x080483d0 = 3.4042736339637191e-68 [BE]
0x080483d8 = 9.4124612178635506e+78 [BE]
EOF
RUN
NAME=pf z, scr.strconv and str.escbslash
FILE==
CMDS=<<EOF
e asm.arch=x86
wz \x7fabc\\123\n
(print strconv escbslash; e scr.strconv=${strconv}; e str.escbslash=${escbslash}; pf z)
.(print asciiesc false)
.(print asciiesc true)
.(print asciidot false)
.(print asciidot true)
EOF
EXPECT=<<EOF
0x00000000 = "\x7fabc\\123\n"
0x00000000 = "\x7fabc\\123\n"
0x00000000 = "\x7fabc\\123\n"
0x00000000 = "\x7fabc\\123\n"
EOF
RUN
NAME=pfj and triply-nested struct
FILE==
CMDS=<<EOF
e asm.arch=x86
wv2 0x1234
wv4 0x56789abc @ 0x2
wv8 0xdef0123456789abc @ 0x6
pfn third "x2 t1"
pfn second "?x4 (third)t s1"
pfn first "?x8 (second)s f1"
pf. first
echo
pf.j first~{}
EOF
EXPECT=<<EOF
0x00000000 : s = struct<second> {
0x00000000 : t = struct<third> {
0x00000000 : t1 = 0x1234 [LE]
}
0x00000002 : s1 = 0x56789abc [LE]
}
0x00000006 : f1 = 0xdef0123456789abc [LE]
[
{
"name": "s",
"type": "unknown",
"offset": 0,
"struct_type": "second",
"fields": [
{
"name": "t",
"type": "unknown",
"offset": 0,
"struct_type": "third",
"fields": [
{
"name": "t1",
"type": "hex",
"size": 2,
"offset": 0,
"endian": "little",
"value": 4660
}
]
},
{
"name": "s1",
"type": "hex",
"size": 4,
"offset": 2,
"endian": "little",
"value": 1450744508
}
]
},
{
"name": "f1",
"type": "hex",
"size": 8,
"offset": 6,
"endian": "little",
"value": 16064359886828903100
}
]
EOF
RUN
NAME=pfj and Matryoshka dolls
FILE==
CMDS=<<EOF
e asm.arch=x86
wx 7f
wv8 0xdef0123456789abc @ 0x1
pfn fourth "x1 fo1"
pfn third "? (fourth)fo"
pfn second "? (third)t"
pfn start "?x8 (second)s f1"
pf. start
echo
pf.j start~{}
echo
pfn full "? (second)s"
pf. full
echo
pf.j full~{}
EOF
EXPECT=<<EOF
0x00000000 : s = struct<second> {
0x00000000 : t = struct<third> {
0x00000000 : fo = struct<fourth> {
0x00000000 : fo1 = 0x7f [LE]
}
}
}
0x00000001 : f1 = 0xdef0123456789abc [LE]
[
{
"name": "s",
"type": "unknown",
"offset": 0,
"struct_type": "second",
"fields": [
{
"name": "t",
"type": "unknown",
"offset": 0,
"struct_type": "third",
"fields": [
{
"name": "fo",
"type": "unknown",
"offset": 0,
"struct_type": "fourth",
"fields": [
{
"name": "fo1",
"type": "hex",
"size": 1,
"offset": 0,
"endian": "little",
"value": 127
}
]
}
]
}
]
},
{
"name": "f1",
"type": "hex",
"size": 8,
"offset": 1,
"endian": "little",
"value": 16064359886828903100
}
]
0x00000000 : s = struct<second> {
0x00000000 : t = struct<third> {
0x00000000 : fo = struct<fourth> {
0x00000000 : fo1 = 0x7f [LE]
}
}
}
[
{
"name": "s",
"type": "unknown",
"offset": 0,
"struct_type": "second",
"fields": [
{
"name": "t",
"type": "unknown",
"offset": 0,
"struct_type": "third",
"fields": [
{
"name": "fo",
"type": "unknown",
"offset": 0,
"struct_type": "fourth",
"fields": [
{
"name": "fo1",
"type": "hex",
"size": 1,
"offset": 0,
"endian": "little",
"value": 127
}
]
}
]
}
]
}
]
EOF
RUN