Hello all!!

Pcode is totally different than Native.  When a VB prog is compiled to native code, you get ASM just like with any C prog.  Pcode is short for Psuedo Code or in the old days Pascal Code.  The advantages of this are

1) Smaller .exe
2) A LOT easier to crack :)

Pcode progs have "Procedures" just like every other program, except they are different in many ways.  Below I'll show some code from WP's crackme and explain it as best as I can.  I know that ExDec should show more bytes, but I'm busy with a lot of other things atm.. sorry.

A typical proc would consist of a block of bytes.  Each byte "calls" a particular section of code inside MSVBVM*.DLL unless it is a "parameter" byte.  Below I only show the bytes that represent the particular excodes.  27 = LitVar_Missing, 04 = FLdRfVar, 1b = LitStr......  There ARE more bytes behind them, but I don't show them yet (lame or not?)  

403368: 27 LitVar_Missing 
40336B: 27 LitVar_Missing
40336E: 3a LitVarStr:              ( local_00D0 ) About

403368 is the RVA of this instruction.  So what you want to do is BPM this address if you are interested in looking at this particular instruction.  The next address is 40336B, so you just subtract that from the previous address and you the the real length of the instruction which is 3 bytes long.  So you have 0x27 followed by 2 bytes of "parameters"


As you can see, the proc "starts" with Proc: 403400 This is because Pcoded progs have a pointer at the END of the procedure to a table to use.  When there is a call, I'll show it like this.

 Proc: 403400

403368: 27 LitVar_Missing          //MsgBox() takes 5 parameters.  Sometimes some of them are
40336B: 27 LitVar_Missing          //NULL or MISSING
40336E: 3a LitVarStr:              ( local_00D0 ) About //This is a local parameter (local_00D0)
				  			//it is the location and "About" is what
							//is stored there. 	

403373: 4e FStVarCopyObj           local_00E0		//II is then copied to local_00E0.
403376: 04 FLdRfVar                local_00E0		//Now we "push" it onto the "stack"
403379: f5 LitI4:                  0x40  64  (...@)	//This is the style of MsgBox() to show.

40337E: 1b LitStr:                 Well, kewl. you found the about box.	
					//Anytime you see  
					//LitStr: it is a Literal String.  These are very helpful
					//when finding nags or error messages :)

403381: 1b LitStr:			//Just space.                  
403384: 2a ConcatStr              	//ConcatStr puts 2 strings together.
403385: 23 FStStrNoPop             local_0088	//Local variable which stores the address of 
						//the next line of text.

403388: 1b LitStr:                 this crackme is quite a bit easier than 

						//We continute to put the string together

40338B: 2a ConcatStr              
40338C: 23 FStStrNoPop             local_008C
40338F: 1b LitStr:                  
403392: 2a ConcatStr              
403393: 23 FStStrNoPop             local_0090
403396: 1b LitStr:                 my crackme #2 [the matrix one]. so 
403399: 2a ConcatStr              
40339A: 23 FStStrNoPop             local_0094
40339D: 1b LitStr:                  
4033A0: 2a ConcatStr              
4033A1: 23 FStStrNoPop             local_0098
4033A4: 1b LitStr:                 rather than sniff a serial why not make 
4033A7: 2a ConcatStr              
4033A8: 23 FStStrNoPop             local_009C
4033AB: 1b LitStr:                  
4033AE: 2a ConcatStr              
4033AF: 23 FStStrNoPop             local_00A0
4033B2: 1b LitStr:                 a key generator. 
4033B5: 2a ConcatStr              
4033B6: 23 FStStrNoPop             local_00A4
4033B9: 1b LitStr:                  
4033BC: 2a ConcatStr              
4033BD: 23 FStStrNoPop             local_00A8
4033C0: 1b LitStr:                   
4033C3: 2a ConcatStr              
4033C4: 23 FStStrNoPop             local_00AC
4033C7: 1b LitStr:                  
4033CA: 2a ConcatStr              
4033CB: 23 FStStrNoPop             local_00B0
4033CE: 1b LitStr:                 You MAY patch the opening NAG. 
4033D1: 2a ConcatStr              
4033D2: 46 CVarStr                 local_00C0
4033D5: 0a ImpAdCallFPR4:          _rtcMsgBox		//This is the call to MsgBox()
4033DA: 32 FFreeStr					//We have to free all resources used
4033F3: 36 FFreeVar
4033FE: 13 ExitProcHresult			//Exit this procedure.  Notice 0x13 is
						//the byte that represents ExitProcHresult.       


Ok, that's one of the smaller procs inside WP's crackme.  As you can see there is a LOT of repetition going on here with all the ConcatStr's :)  You usually won't see something this long. Now I'll show you a few tricks you can use to defeat this crackme.  This whole tute may end up being very long, so grab a soda or your favorite drink and relax :)

 

When we first run the crackme, we are greeted by a messagebox.  I selected ok, and was then greeted by yet another one.  After this one, there was nothing... hmmm :)  I have tried to put the first block of code executed at the beginning of the output when disassembling.  So taking a look at it, i search for Welcome, and find it.  Again this is just like the above code except its a little more complicated.
Proc: 4051f4
403EA8: f5 LitI4:                  0x57  87  (...W)	//LitI4 is a Literal Integer covering 4
							//bytes.
403EAD: 0b ImpAdCallI2             _rtcBstrFromAnsi	//Call Chr$()
403EB2: 31 FStStr                  local_0370		//Store it here.. address is used later
403EB5: f5 LitI4:                  0x61  97  (...a)	//Repeat until done
403EBA: 0b ImpAdCallI2             _rtcBstrFromAnsi
403EBF: 31 FStStr                  local_0374
403EC2: f5 LitI4:                  0x72  114  (...r)
403EC7: 0b ImpAdCallI2             _rtcBstrFromAnsi
403ECC: 31 FStStr                  local_0378
403ECF: f5 LitI4:                  0x65  101  (...e)
403ED4: 0b ImpAdCallI2             _rtcBstrFromAnsi
403ED9: 31 FStStr                  local_037C
403EDC: f5 LitI4:                  0x7a  122  (...z)
403EE1: 0b ImpAdCallI2             _rtcBstrFromAnsi
403EE6: 31 FStStr                  local_0380
403EE9: f5 LitI4:                  0x50  80  (...P)
403EEE: 0b ImpAdCallI2             _rtcBstrFromAnsi
403EF3: 31 FStStr                  local_0384
403EF6: f5 LitI4:                  0x75  117  (...u)
403EFB: 0b ImpAdCallI2             _rtcBstrFromAnsi
403F00: 31 FStStr                  local_0388
403F03: f5 LitI4:                  0x70  112  (...p)
403F08: 0b ImpAdCallI2             _rtcBstrFromAnsi
403F0D: 31 FStStr                  local_038C
...
...
...
4042B8: 27 LitVar_Missing         	//explained earlier
4042BB: 27 LitVar_Missing         
4042BE: 3a LitVarStr:              ( local_031C ) Welcome
4042C3: 4e FStVarCopyObj           local_032C
4042C6: 04 FLdRfVar                local_032C
4042C9: f5 LitI4:                  0x40  64  (...@)
4042CE: 3e FLdZeroAd               local_0370		//notice the address here.  It is the 
							//same as above.

4042D1: 23 FStStrNoPop             local_0088		//Push it on the stack
4042D4: 3e FLdZeroAd               local_0374
4042D7: 23 FStStrNoPop             local_008C
4042DA: 2a ConcatStr              
4042DB: 23 FStStrNoPop             local_0090
4042DE: 3e FLdZeroAd               local_0378
4042E1: 23 FStStrNoPop             local_0094
...
...
repeat for a LONG time
...
...
4045E7: 46 CVarStr                 local_030C
4045EA: 0a ImpAdCallFPR4:          _rtcMsgBox		//Finally we get to our "Nag"
4045EF: 32 FFreeStr
4047CE: 36 FFreeVar

Looking a little further down, we see this:

404897: 3a LitVarStr:              ( local_031C ) C:\WINDOWS\SMRTCHCK.TSF

					//Hmmm... windows directory and smrtchck.  Could this be
					//a check to see if we have smartcheck installed?
			
40489C: 4e FStVarCopyObj           local_030C
40489F: 04 FLdRfVar                local_030C
4048A2: 0b ImpAdCallI2             _rtcDir	//Hehe... Getting a directory search for it :)
4048A7: 46 CVarStr                 local_032C
4048AA: Lead1/f6 FStVar           
4048AE: 35 FFree1Var               local_030C
4048B1: 04 FLdRfVar                local_04E0
4048B4: 3a LitVarStr:              ( local_031C ) 
4048B9: 5d HardType               
4048BA: Lead0/40 NeVarBool		//There are several "compares" in pcode.  This is
					//one of them.  NeVarBool = Not Equal Variable Bool.
					//Bool = 0 or 1

4048BC: 1c BranchF:                4051F2	//If it was not found, then we branch to the
						//end of this proc and continue on like normal


Here I need to explain how jumps work in pcode.  The beginning of the procedure is the BASE of all jump operations.  Lets say you have 0x1C 0x02 0x00 in this procedure.  0x1C = Branch if False, and 0x0002 is the distance from the start of the procedure to jump... NOT the distance from the current location (unlike ASM).  So when we want to make our own jumps, we need to calculate the distance to jump ourselves (which isn't very hard).  We just take the destination and stubract the starting point from it.. and we get our distance :)
1C = BranchF
1D = BranchT
1E = Branch



4048BF: f5 LitI4:                  0x57  87  (...W)
4048C4: 0b ImpAdCallI2             _rtcBstrFromAnsi
4048C9: 31 FStStr                  local_0370
4048CC: f5 LitI4:                  0x61  97  (...a)
4048D1: 0b ImpAdCallI2             _rtcBstrFromAnsi
4048D6: 31 FStStr                  local_0374
4048D9: f5 LitI4:                  0x72  114  (...r)
4048DE: 0b ImpAdCallI2             _rtcBstrFromAnsi
4048E3: 31 FStStr                  local_0378
4048E6: f5 LitI4:                  0x65  101  (...e)
...
...
lots of boring stuff
...
...
405001: 0a ImpAdCallFPR4:          _rtcMsgBox	//shows us our 2nd nag
405006: 32 FFreeStr
4051E5: 36 FFreeVar
4051F0: Lead1/c8 End				//Terminates the program!              
4051F2: 13 ExitProcHresult        		//4048bc branches here if all is successful


OK!  Now we know what this crackme does, but how to defeat it?  Well there are a few possibilities here.  We can patch the beginning to jump to the end.  We can just patch the beginning to return.  We can patch the beginning to jump to the check and then patch that also.  I'll show you how to do each of them.  Before you attempt any of this, make a backup copy of the crackme.  It will be easier to just replace the file than it will be to unpatch the patches (if you want to try each method).

1) First we'll patch the beginning of the proc to jump to the end.  

Proc: 4051f4
403EA8: f5 LitI4:                  0x57  87  (...W)     //Notice we have 5 bytes to work with.						                //Unlike ASM, you don't have to worry 							        //about replacing the extra bytes
							//with NOPs.  (403EAD - 403ea8 = 5 bytes)
								
403EAD: 0b ImpAdCallI2             _rtcBstrFromAnsi
...
...
...
4051E5: 36 FFreeVar
4051F0: Lead1/c8 End              
4051F2: 13 ExitProcHresult        

A jump requires 3 bytes.  You need to select the jump you want. 1C - BranchF, 1D - BranchT ,1E - Branch.  Next we need to select the required distance.  Find the beginning of the proc (403EA8) and stubtract it from the end of the proc (4051f2) and you get 134A.  REMEMBER!!! When you patch the program, this is data and it needs to be in reverse order.   We don't want to jump to 4051f0 because this will end our program.  So.... using hiew (it shows RVA.. or any other program that will show it).  We goto 403EA8 and replace what's there with 1E4A13.  When we run it, no nag!  


2) Next we'll just return from the proc.

Again, goto 403EA8 and this time, we only need to change the first byte to 13.  This is a lot easier and quicker :)   *NOTE* doing 1 and 2 will give you a regular window and clicking in the upper middle will give you the about box :)


3) Finally we'll patch the beginning to jump to the check and then patch that also.

4047F0: 04 FLdRfVar                local_04CC
4047F3: 21 FLdPrThis              
4047F4: 0d VCallHresult            7b3fbe48

This is where the FIRST nag really ends.  There is a check just before this for a return code from the messagebox, but we don't need to worry about this.  So again, we subtract the start address from this address and get 0948.  So we goto the start of the proc and change the bytes to 13 48 09.  Now that we are jumping to the check for smartcheck, we need to patch here as well (otherwise if someone has it installed, the 2nd nag will appear then the program will end).
404897: 3a LitVarStr:              ( local_031C ) C:\WINDOWS\SMRTCHCK.TSF
40489C: 4e FStVarCopyObj           local_030C
40489F: 04 FLdRfVar                local_030C
4048A2: 0b ImpAdCallI2             _rtcDir
4048A7: 46 CVarStr                 local_032C
4048AA: Lead1/f6 FStVar           
4048AE: 35 FFree1Var               local_030C
4048B1: 04 FLdRfVar                local_04E0
4048B4: 3a LitVarStr:              ( local_031C ) 
4048B9: 5d HardType               
4048BA: Lead0/40 NeVarBool        
4048BC: 1c BranchF:                4051F2

In this area we have 2 choices.  1) Change  C:\WINDOWS\SMRTCHCK.TSF to something different (It is in WIDE CHARACTER FORMAT.  This means that you will see C.:.\.W.I.N.D.O.W.S.\.  inside the .EXE with a hexer.  Instead of SMRTCHCK.TSF, change it to .FSF or something harmless. OR the 2nd choice 2) Change the BranchF as 4048BC to a constant jump.  To do this just goto that address and change 1C to 1E :)  When we do this, we get an oval shaped window and when we click on the top, we get the about box :)


The code that is responsible for this is between 4047F0 and 404891, but for this tute (and until I make exdec better) I won't go into that, but basically it calls CreateEllipticRgn() and probably SetWindowRgn().


Now onto the registration part :)

**** I'm not going to go into great detail here.. just show you how to get a correct serial****

Scanning through the deadlisting, I noticed:

403D6B: 04 FLdRfVar                local_017C
403D6E: Lead0/ef ConcatVar        
403D72: 3a LitVarStr:              ( local_014C ) -DSP
403D77: Lead0/ef ConcatVar        			//More concatenation

403D7B: Lead0/33 EqVarBool		//EqVarBool returns 0/1 depending on the result of the
					//compare.  This needs a little explanation. 
					//    *Read at the bottom*
						
403D7D: 32 FFreeStr
403D84: 1a FFree1Ad                local_00A0
403D87: 36 FFreeVar
403D9A: 1c BranchF:                403E14		//Branch past the Congratulations screen
403D9D: 04 FLdRfVar                local_0180
403DA0: 21 FLdPrThis              
403DA1: 0f VCallAd                 7b3fc350
403DA4: 19 FStAdFunc               local_00A0
403DA7: 08 FLdPr                   local_00A0
403DAA: 0d VCallHresult            7b3fbe88
403DAF: 27 LitVar_Missing         
403DB2: 27 LitVar_Missing         
403DB5: 3a LitVarStr:              ( local_00CC ) Crackme #3
403DBA: 4e FStVarCopyObj           local_00FC
403DBD: 04 FLdRfVar                local_00FC
403DC0: f5 LitI4:                  0x40  64  (...@)
403DC5: 1b LitStr:                 Congratulations,  
403DC8: 6c ILdRf                   local_0180
403DCB: 2a ConcatStr              
403DCC: 23 FStStrNoPop             local_0184
403DCF: 1b LitStr:                  you have cracked me. now go keygen me 


*

There are many types of compares.  The compare is NOT done inside the EXE, but inside msvbvm*.dll  This means that if you want to find out what is being compared, you have to either BPM early enough to snoop around, OR enter a call inside the particular compare.  Once inside, you  you will have to trace for a few seconds and then you will see both things being pushed, and then a call directly afterwards.  So to find out what our serial is supposed to be, we need to BPM 403D7B.  This is actually the instruction BEFORE the compare, but this gives us time to get used to what we are seeing.  



OK!!  In order to crack pcoded apps, you CAN'T use traditional methods.  You MUST bpm the address you want to break on.  m$'s Virtual Machine reads a byte at a memory location and then runs pre-made code.  If you are planning on attempting a lot of pcoded apps, I would suggest you load the symbols into sice. Remember that the last ones loaded will be the ones used, so if you load vb5 first then vb6 symbols, vb6 will be the ones you work with even if you are trying to crack a vb5 app. As always, you can get the latest version of ExDec, the symbols, and any tutorials at http://members.xoom.com/c4n4ever/.space/    msdbg.zip contains the symbols for vb5 and 6.  The other zips are the old version of ExDec and the newer betaexdec.zip.  

Please email me with any problems or questions at josephco_@hotmail.com 

I will be glad to answer any questions you may have, or to help you in writing a tutorial for a crackme.  Please remember that ExDec is still under construction, and that it has a LOT more vb5 suport than vb6.  ALSO ExDec is only for progs compiled to PCODE.  To crack native, use w32dasm/IDA, and sice.  

joe