vb6 PCode NOP
Author: David Zimmer
Date: 08.29.19 - 10:02pm
I have not yet seen a true one byte NOP instruction for vb6 pcode. Now I have not yet googled for this, but just saw some discussion saying they couldnt find one and I had a fun thought how we can easily MAKE one.
Going back to the source in our previous post consider the following disasm
401D88 Form1.Form_Load: 401D88 F5 04000000 LitI4 0x4 401D8D F5 03000000 LitI4 0x3 401D92 F5 02000000 LitI4 0x2 401D97 F5 01000000 LitI4 0x1 401D9C 05 0000 ImpAdLdRf Module1.Proc_401DD8 401D9F 0A 01001400 ImpAdCallFPR4 user32.CallWindowProcA 401DA4 3C GetLastError 401DA5 FCC8 End <-- nop 401DA7 13 ExitProcHresultThis is a perfect example to try, how can we easily eliminate the end call? In this situation we could easily move the ExitProc up but that wont work in very many situations. I want a true one byte nop that has no consequences and can be used anywhere, and I know exactly how to do it easily.
In the opcode handler tables there are plenty of slots which are unused. They are all filled with an invalid opcode handler that just raises an exception just in case they are somehow hit.
ENGINE:66106D14 BE 4F 10 66 _tblByteDisp dd offset _lblEX_Bos ENGINE:66106D18 23 C4 10 66 dd offset InvalidExCode ENGINE:6610C423 InvalidExCode ENGINE:6610C423 push 33h ENGINE:6610C425 call _EbRaiseExceptionCodeOk perfect opcode 01 is easy to remember and is a free slot vb will never use. Now we need to find the right block of asm we can re-use?
ENGINE:66105049 _lblEX_StAry ENGINE:66105049 call ___vbaAryMove@8 ENGINE:6610504E xor eax, eax ENGINE:66105050 mov al, [esi] ENGINE:66105052 inc esi ENGINE:66105053 jmp ds:_tblByteDisp[eax*4]Do you see what I see? Got lucky and found this on literally the second try when i scrolled down a few lines from my first instinct of looking at opcode 00 Bos* (see end for details on Bos)
Yeah, all we have to do is change 66106D18 to point to 6610504E and opcode 01 goes from invalid to a perfect one byte nop. (Thats table 5, index 1 for those keeping track)
ENGINE:66108114 tableLead4 dd offset _lblEX_FnStrComp3Var ENGINE:66108118 dd offset _lblEX_StAryYou could patch your runtime on disk or with an injection dll. You could probably even use a sdb shim to patch it but never tried. Anyway since my debugger stuffs a dll into the target process and I am already dynamically locating and patching the opcode tables, this one is a gimmie for use while debugging in vbdec. Going to include it as a little bonus for sure.
Tested in manually in the debugger and worked perfect. Just a fun little find, smallest of tweaks really.
LargeBos: What the heck I am on a roll, you see this instruction everywhere but what does it do? Name makes no sense. Even knowing what it does name still makes no sense.
It takes two bytes off the stream as a word which are cur function start + delta to calculate a new address in the current function.
This address is stored in the vb runtime house keeping area of the stack at ebp-14h. This sets where to resume execution at the asm which is beginning of the next source line for routines which use On Error Resume Next.
I have renamed it ErrNext in my disasm routines.
Final fun fact, there is no On Error Resume Next opcode. They use OnError with the handler address set to 0xFFFF (or -1 to us humans)
Edit: So I did some googling and I found that people did find a natural 2 byte NOP in the form of:
ENGINE:661051E9 _lblEX_CI2UI1 ENGINE:661051E9 xor eax, eax ENGINE:661051EB mov al, [esi] ENGINE:661051ED inc esi ENGINE:661051EE jmp ds:_tblByteDisp[eax*4]This is table 2 index 14, so would require a FC14 as referenced in Eternal Bliss VBCrackMe
Comments: (1)On 08.30.19 - 1:31pm Dave wrote: