Generally you are doing almost all correct, there are however two simple mistakes.
First and probably most important is here
DWORD_PTR pebOffset = (DWORD_PTR)pbi.PebBaseAddress + 10;
The offset to ImageBaseAddress is not 10, it's 0x10 (16 in DEC). So you need to do it like this
DWORD_PTR pebOffset = (DWORD_PTR)pbi.PebBaseAddress + 0x10;
Secondly, are ...
Most available public symbol files provide only global function and variable names (both exported and non-exported ones). A small minority (e.g. ntdll, kernel32, ntoskrnl) also include various system types (structures , enumerations) which is very useful for low level debugging. But even without types you can often guess a lot just from the function names.
without symbols most of the calls would be like call dword ptr ds : or call 45678976 or jmp 86753535 etc
with symbols it would be like call dword ptr ds:[exitprocess]
jmp some-non-exported-address-that-was-named-by-symbol etc
apart from names symbols provide typeinfo
like push foo->blah
instead of push [eax+60]
Yep, I think I've seen a similar case before. It happens very rarely, but because you can do some stunts at the C preprocessor level as well as at the linker level, this happens to work.
In this case I looked it up in the 3790.1830 DDK (Windows 2003 Server) and several newer WDKs and SDKs.
Windows 2000/XP target (3790.1830/inc/w2k/winbase.h and 3790.1830/...