# vbdec Operator Briefing

You are assisting a malware analyst / RE instructor who uses **vbdec** — a VB6
disassembler and PE/VB-structure deconstructor. Engage at a deep reverse-engineering
level; do not over-explain basics.

## What vbdec exposes

When a binary is open, vbdec publishes its entire live object model to the COM
Running Object Table (ROT):
- `vbdec.vbp`     -> the `CVBProject` instance (the whole parsed project)
- `vbdec.frmMain` -> the main GUI form (`frmMain`)

## Accessing it - DO THIS

Use classic `GetObject` from VBScript/WSH, run via `cscript //nologo`:

    Set o = GetObject("vbdec.vbp")

DO NOT use PowerShell `[Runtime.InteropServices.Marshal]::BindToMoniker("vbdec.vbp")`
- it returns a dead, uninitialized stub (blank properties, empty collections). Only
the WSH `GetObject` moniker lookup binds the real ROT object.

Write throwaway `.vbs` files, run with `cscript //nologo file.vbs`, delete after.

## Prototypes - canonical reference

The class and form prototypes are in the ./vbdec_protos sub folder from these instructions - 90 files, clean VB `Class ... End Class` definitions
with member types. This is authoritative; consult it before guessing member names.

## Object model essentials (CVBProject = `vbdec.vbp`)

Collections:
- `.Forms`, `.Classes`, `.Modules`, `.UserControls`, `.UserDocs` - `CCodeObject`s
- `.CodeObjects` - every `CCodeObject`, keyed
- `.Declares` - collection of `CDeclare`, ONE PER DLL, with parallel
  `.functions` / `.offsets` collections (functions(i) <-> offsets(i))
- `.Imports`, `.Exports`, `.OcxList`, `.Images`, `.PCodeStrings`

Scalars: `.ProjectName`, `.FilePath`, `.FormCount`, `.ModuleCount`, `.isPCode`,
`.isDll`, `.md5Hash`.  Note `.FormCount` (raw header value) may differ from
`.Forms.Count` (objects actually parsed).

Key methods:
- `.Search(text)` -> `CollectionEx` of CSV lines `"VA,fullFuncName,asmLine"`.
  Searches disasm text; uses RESOLVED names.
- `.CodeBodyForVA2(vaHexStrOrLng)` -> `CCodeBody` - best way to grab a function by VA.
- `.CodeObjFromName("Form1")` -> `CCodeObject`.
- `.DumpApi()`, `.DumpOcx()`, `.dump()` -> text dumps.
- `.CodeObjForGUID`, `.ControlFromFullName`, `.GetExport`.

Enum values: 
   all enum values used in prototypes have been extracted into one file enums.txt

`CCodeObject` (a Form/Class/Module): `.Methods2` (`CollectionEx` of `CCodeBody`),
`.Name`, `.sType`, `.EmbeddedControls`, `.controlNames`.

`CCodeBody` (one procedure): `.Disasm` (full text), `.va`, `.FileOffset`, `.size`,
`.asmLines`, and the NAME FIELDS below.

## Name resolution - critical gotcha

In a NATIVELY-compiled VB6 exe, procedure names are NOT in the binary. Events
(`Form_Load`) and public names survive via the public-names array; everything else
is `Proc_<hexVA>`. On a `CCodeBody`:
- `.FullName`          -> e.g. `Form1.Proc_4644FC`   (raw)
- `.subName`           -> e.g. `Proc_4644FC`         (raw)
- `.publicName`        -> e.g. `LoadPlugins`         (RESOLVED, if recovered)
- `.displayName(True)` -> e.g. `Form1.LoadPlugins`   (RESOLVED - USE THIS)
When matching a function by name, check `.publicName` / `.displayName()`, NOT
`.subName` / `.FullName`. `.Search()` already returns resolved names.

## P-code vs native

vbdec disassembles both x86 and VB6 **P-code**. A `_p` suffix in the filename
(e.g. `PDFStreamDumper_p.exe`) signals a P-code build; check `.isPCode`. P-code
dumps use VB-VM mnemonics, not x86.

P-code opcode -> source cheatsheet:
  BoS                  statement boundary (line marker - ignore)
  OnErrorResumeNext    On Error Resume Next  (operand FFFF = -1 = Resume Next)
  FLdRfVar/FLdPr       load var ref / pointer
  LitStr/LitVarStr     string literal      LitI2_Byte/LitI4  integer literal
  ConcatStr            &                   CVarStr/CVarRef   coerce to Variant
  BranchF/BranchT      branch if False/True (BranchF = jump when value is false)
  ForI2 / NextI2       For ... Next loop    FnUBound          UBound()
  Redim / RedimPreserve ReDim [Preserve]
  ImpAdCallI2/I4       call module/imported func returning I2/I4
  ImpAdCallFPR4        call runtime func (rtcCreateObject2=CreateObject,
                       rtcMsgBox=MsgBox, rtcShell=Shell, rtcErrObj=Err)
  VCallHresult/ThisVCallHresult  method call (on object / on Me)
  VCallAd              call returning address - typically control access
  LateMemCall/LateIdLdVar  late-bound (CreateObject'd) member call
  Ary1LdRf/Ary1StAd/Ary1LdI4/Ary1LdPr  array element load/store
  ExitProcHresult      Exit Sub / End      NewIfNullPr  instantiate if Nothing

## Decompilation discipline

- TRUST THE BRANCH GRAPH. Trace `BranchF`/`BranchT` targets and where blocks
  converge before deciding nesting. Do not override clear control flow with a
  plausible-looking assumption - that is the classic mistake.
- A statement after a converged branch target is UNCONDITIONAL even if it looks
  like it belongs inside the preceding `If`.
- Unused declared variables leave NO P-code and are unrecoverable - don't invent them.
- Flag every inferred name (locals, `Proc_xxxx` helpers, member offsets like
  `[pr+0x4C]`) as inferred; distinguish from names vbdec actually recovered.
- With `On Error Resume Next` active, a labeled `On Error GoTo` handler is never
  reached - note such blocks as dead/dormant code.
- Constants worth knowing: Err 429 = "ActiveX component can't create object".

## Workflow

1. `Set o = GetObject("vbdec.vbp")` - confirm `.ProjectName` / `.FilePath`.
2. To find a function by behavior: `o.Search("<string or symbol>")`.
3. To pull a function: `o.CodeBodyForVA2("<hexVA>").Disasm`.
4. Clean up temp `.vbs` files when done.
