Understand VB6 disassemble code - vb6

I have an old VB executable that has been used for a long time in my project.
The current implementation of the application contains a debug window that's
not needed any more.
Of course, the source code was lost and can not be modified.
My idea is to modify the HEX code of the instance that's opening the annoying debug window.
For that purpose, I use VB Decompiler by DotFix software, and I suppose that I found the code responsible for that instance. Unfortunately, I can't understand how it works.
Let's see the disassemble code:
loc_8F420C: var_8A = 0
loc_8F4219: If (Len(var_88) = &H30) Then
loc_8F4225: Call {3014B1BF-8A2C-23D7-B50400C24F280C20}.Method_arg_12 (var_88)
loc_8F4233: Call {3014B1BF-8A2C-23D7-B50400C24F280C20}.Method_arg_16 (var_108)
loc_8F423D: If CBool(var_108) Then
loc_8F424D: Me.Global.Unload Me
loc_8F4258: Else
loc_8F425A: var_8A = &HFF
...
loc_8F43B0: End If
loc_8F43B3: Else
At the first sight var_108 seems a bool variable that is the one setting the debug window. Can I implicitly put in loc_8F423D: If CBool(false/true) Then to stop this window from launching?
Can anyone explain to me what are those Call {#######-####-####-################}.Method_arg_## from above?
PEiD detect compiler:
Microsoft Visual Basic 5.0 / 6.0 [Overlay]
Part 2:
It took me a long time to get the new idea - the right one, possibly. Let's take a look at the assembly code:
004F420C: 70 FStI2 var_8A <- loc_8F420C: var_8A = 0
Looks like loc_8F4219: If (Len(var_88) = &H30) Then
004F420F: 6C ILdRf var_88
004F4212: 4A FnLenStr Len()
004F4213: F5 LitI4: 48 (0x30)
Let's find the next code snippets:
004F4218: C7 EqI4 =
004F4219: 1C BranchF 004F43B3
Our Call methods looks like :
004F421C: 6C ILdRf var_88 < - (var_88) from Call
004F421F: 22 ImpAdLdPr
004F4222: 58 MemLdPr
004F4225: 0D VCallHresult var_88.vtable[12] <- Method_arg_12
004F422A: 04 FLdRfVar var_108 <- (var_108) possible CALL/BACK
004F422D: 22 ImpAdLdPr
004F4230: 58 MemLdPr
004F4233: 0D VCallHresult var_108.vtable[16] <- Method_arg_16
004F4238: 6C ILdRf var_108 <- (var_108) 70% sure is RESPONSE(true/false)
And now the most interesting parts of that annoying P-Code&Assembly, we find the if instance that verifies if the Debug Windows is needed. If we look at P-Code we can see that if has the form:
loc_8F423D: If CBool(var_108) Then
loc_8F424D: Me.Global.Unload Me
loc_8F4258: Else
loc_8F425A: var_8A = &HFF
And now look at the Address - if is true execute address 00F424D / 8F424D else jump outside to 004F4258
004F423B: FC52 CBoolI4
004F423D: 1C BranchF 004F4258
004F4240: 6C ILdRf param_8
004F4243: FD9C FStAdNoPop
004F4247: 05 ImpAdLdRf
004F424A: 24 NewIfNullPr GLOBAL
004F424D: 0D VCallHresult Global._Unload(object As IDispatch)
004F4252: 1A FFree1Ad var_90
004F4255: 1E Branch 004F43B0
004F4258: loc_004F423D
004F4258: F4 LitI2_Byte: 255 (True)
Possibly, if I change the 004F423D: 1C BranchF 004F4258 so that it points to another address 004F424D, logically that might do the trick.
004F423D: 1C BranchF 004F424D
Now I'm trying to find that address with OllyDbg - to test if that helps. If I succeed I will write part 3.
Does anyone have some other ideas?

Related

how to limit 00 to 99 counter to 60

For a simple starter project I was putting together a 2-7segement display 00 to 99 counter coded on sketch.
//The line below is the array containing all the binary numbers for the digits on a SSD from 0 to 9
const int number[11] = {0b1000000, 0b1111001, 0b0100100, 0b0110000, 0b0011001, 0b0010010, 0b0000010, 0b1111000, 0b0000000, 0b0010000};
I believe that my solution is either to change this part of the code or add another line, I'm just unsure.
Any advice?
I have tried adding another line to set one of the displays to stop at 6 but it didn't compile with the rest of the code.

Error: syntax error, unexpected "Identifier", expecting EXTERNAL or GLOBAL

Hi I was wondering if yall could help me figure this error out. Im rather new to cobol as it is my first (and only) cobol class in my major.
I keep getting this error lab3a.cob:23: Error: syntax error, unexpected "Identifier", expecting EXTERNAL or GLOBAL
whenever I try to compile. And I cant seem to see what I'm doing wrong.
My Code
IDENTIFICATION DIVISION.
PROGRAM-ID. "LAB3A".
Author. Fielding Featherston
* Takes inputs from file and seperates.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT InFile
ASSIGN to "lab3-in.dat"
ORGANIZATION is LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD InFile.
01 InString.
05 PIC X(13).
05 Instrument PIC X(12).
88 Brass value "Bugle" "Flugelhorn"
"Sousaphone" "Trombone"
"Trumpet" "Tuba".
88 Percussion value "Bass Drum" "Bells" "Bongos"
"Castanets" "Chimes" "Cymbals"
"Snare Drum" "Xylophone".
88 Strings value "Banjo" "Bass" "Cello" "Guitar"
"Harp" "Lyre"
"Mandolin" "Violin".
88 Woodwind value "Bagpipes" "Bassoon" "Clarinet"
"Flute" "Oboe"
"Piccolo" "Saxophone".
WORKING-STORAGE SECTION.
01 BrassCount PIC 9(3).
01 PerCount PIC 9(3).
01 StringCount PIC 9(3).
01 WoodCount PIC 9(3).
01 OtherCount PIC 9(3).
01 BrassStr PIC ZZ9.
01 PerStr PIC ZZ9.
01 StringStr PIC ZZ9.
01 WoodStr PIC ZZ9.
01 OtherStr PIC ZZ9.
01 InStringLength PIC 99.
01 EndFileStr PIC X VALUE "n".
88 EndFile VALUE "y"
When Set to False is "y".
PROCEDURE DIVISION.
000-Main.
Open Input InFile
Perform until EndFile
Read InFile
At end
Set EndFile to FALSE
Not at End
PERFORM 100-SeperateStrings
PERFORM 200-ClassCount
END-READ
END-PERFORM
CLOSE InFile
Move BrassCount to BrassStr
Move PerCount to PerStr
Move StringCount to StringStr
Move WoodCount to WoodStr
Move OtherCount to OtherStr
DISPLAY "Counts"
DISPLAY " Brass: " FUNCTION TRIM(BrassStr)
DISPLAY " Percussion: " FUNCTION TRIM(PerStr)
DISPLAY " String: " FUNCTION TRIM(StringStr)
DISPLAY " Woodwind: " FUNCTION TRIM(WoodStr)
DISPLAY " OTHER: " FUNCTION TRIM(OtherStr)
STOP RUN.
100-SeperateStrings.
MOVE FUNCTION Length(InString) to InStringLength
UNSTRING InString (14:InStringLength)
INTO Instrument
END-UNSTRING.
200-ClassCount.
IF Brass
Add 1 to BrassCount
ELSE IF Percussion
Add 1 to PerCount
ELSE IF Strings
Add 1 to StringCount
ELSE IF Woodwind
Add 1 to WoodCount
ELSE
Add 1 to OtherCount
END-IF.
An EXTERNAL or GLOBAL clause in the context of the error may only occur in a record description entry; that is, a data entry that begins with 1 or 01. Given that the error occurs between two 88 level items, it appears the compiler is confused about where it is while scanning the source code.
There is some unusual formatting that may be creating a problem with an the compiler. In particular, line 22 contains a number of TAB characters that should not, but may, confuse the compiler. Also, lines 33 and 46 contain a number of TAB characters at the end of each source line causing the lines to exceed 72 characters.
Another possible issue is expansion of tabs, whether each TAB character is replaced by 4 or 8 spaces by the compiler. Again this will affect whether the text exceeds 72 characters. In the absence of a SOURCE FORMAT directive, source text after column 72 is ignored.
Until you know the effect that tabs have on the source code, I suggest replacing all tabs with spaces.

Why am I getting an unexpected `0xcc` byte when loading nearby code bytes? Is it because of segment register %es?

I got some inconsistent result of instruction.
I don't know why this happens, so I suspect %es register is doing something weird, but I'm not sure.
Look at below code snippet.
08048400 <main>:
8048400: bf 10 84 04 08 mov $HERE,%edi
8048405: 26 8b 07 mov %es:(%edi),%eax # <----- Result 1
8048408: bf 00 84 04 08 mov $main,%edi
804840d: 26 8b 07 mov %es:(%edi),%eax # <----- Result 2
08048410 <HERE>:
8048410: 11 11 adc %edx,(%ecx)
8048412: 11 11 adc %edx,(%ecx)
Result 1:
%eax : 0x11111111
Seeing this result, I guessed that mov %es:(%edi),%eax to be something like mov (%edi),%eax.
Because 0x11111111 is stored at HERE.
Result 2:
%eax : 0x048410cc
However, the result of Result 2 was quite different.
I assumed %eax to be 0x048410bf, because this value is stored at main.
But the result was different as you can see.
Question:
Why this inconsistency of the result happens?
By the way, value of %es was always 0x7b during execution of both instruction.
es is a red herring. The difference you see is 1 byte at main, cc vs. bf. That is because you used a software breakpoint at main and your debugger inserted an int3 instruction which has machine code cc temporarily overwriting your actual code.
Do not set a breakpoint where you intend to read from, or use a hardware breakpoint instead which does not modify code.

How to determine the major compiler version from .obj files compiled with /GL?

I'm trying to determine Visual Studio version (2002/2003, 2005, 2008, 2010, 2012, 2013, 2015) from the .obj file generated with the link time code generation option.
The file I have, generated with MSVC2012, has following COFF header contents:
File Header
+0 00 00 Machine - Unknown Machine
+2 FF FF NumberOfSections
+4 01 00 4C 01 TimeDateStamp
+8 70 94 F9 55 PointerToSymbolTable
+12 38 FE B3 0C NumberOfSymbols
+16 A5 D9 SizeOfOptionalHeader
+18 AB 4D Characteristics
Optional Header
+20 AC 9B Magic
+22 D6 B6 Linker Version Major/Minor
It seems that the initial 4 bytes being 00,00,FF,FF mark it as a LTCG object, and what follows is proprietary. None of the usual file header members make "sense" (maybe the timestamp is OK, I didn't check).
Does anyone know offhand if any part of this header is compiler-specific? All I need to determine is the MSVC major version used to compile the object...
It appears that there is a version, coded as <MAJOR:16:LE> 0x80 <MINOR:16:LE>, stored shortly after the header. E.g.:
17.00.61030 -> 0x11.0xEE66 -> 11 00 80 66 EE
19.00.23026 -> 0x13.0x59F2 -> 13 00 80 F2 59
What's needed is to figure out how to get to it reliably by offsets from preceding data.
This is a related question, with no resolution...
TL,DR :
You can't get the compiler version with this file format, I guess ...
Complete answer :
It looks like some variation of the "anonymous file format", described in the "winnth.h" by various ANON_OBJECT_HEADER_XXX structures (replace XXX by V2 or BIGOBJ).
Here is a copy of the ANON_OBJECT_HEADER_BIGOBJ found in winnt.h :
typedef struct ANON_OBJECT_HEADER_BIGOBJ {
/* same as ANON_OBJECT_HEADER_V2 */
WORD Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
WORD Sig2; // Must be 0xffff
WORD Version; // >= 2 (implies the Flags field is present)
WORD Machine; // Actual machine - IMAGE_FILE_MACHINE_xxx
DWORD TimeDateStamp;
CLSID ClassID; // CLSID is a 16 bytes struct (not original comment)
DWORD SizeOfData; // Size of data that follows the header
DWORD Flags; // 0x1 -> contains metadata
DWORD MetaDataSize; // Size of CLR metadata
DWORD MetaDataOffset; // Offset of CLR metadata
/* bigobj specifics */
DWORD NumberOfSections; // extended from WORD
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
} ANON_OBJECT_HEADER_BIGOBJ;</code>
The description match:
Sig1 : 00 00
Sig2 : FF FF
Version : >=2
Machine : 0x14c`
The other header structures (i.e, ANON_OBJECT_HEADER and ANON_OBJECT_HEADER_V2) are basically the same, but with less fields.
For the Version field, I found some information here :
http://www.geoffchappell.com/studies/msvc/link/dump/infiles/obj.htm
Looks like the Version field is "1" for anonymous files, and it seems like the anonymous files and the so called "import files" shared the same characteristics, only that Version = 0 for import file format (I do not really know what it is admittedly).
But yeah, by just looking at the header, it seems that we have no information on what compiler version was used. And even then, when looking at .obj files generated with the /GL switch, they do not exactly follow this format and I didn't find much information about them. I'll be glad that someone prove me wrong.

Getting GCC to optimize hand assembly

In an attempt to make GCC not generate a load-modify-store operation every time I do |= or &=, I have defined the following macros:
#define bset(base, offset, mask) bmanip(set, base, offset, mask)
#define bclr(base, offset, mask) bmanip(clr, base, offset, mask)
#define bmanip(op, base, offset, mask) \
asm("pshx");\
asm("ldx " #base);\
asm("b" #op " " #offset ",x " #mask);\
asm("pulx")
And they work great; the disassembled binary is perfect.
The problem comes when I use more than one in sequence:
inline void spi_init()
{
bset(_io_ports, M6811_DDRD, 0x38);
bset(_io_ports, M6811_PORTD, 0x20);
bset(_io_ports, M6811_SPCR, (M6811_SPE | M6811_DWOM | M6811_MSTR));
}
This results in:
00002227 <spi_init>:
2227: 3c pshx
2228: fe 10 00 ldx 0x1000 <_io_ports>
222b: 1c 09 38 bset 0x9,x, #0x38
222e: 38 pulx
222f: 3c pshx
2230: fe 10 00 ldx 0x1000 <_io_ports>
2233: 1c 08 20 bset 0x8,x, #0x20
2236: 38 pulx
2237: 3c pshx
2238: fe 10 00 ldx 0x1000 <_io_ports>
223b: 1c 28 70 bset 0x28,x, #0x70
223e: 38 pulx
223f: 39 rts
Is there any way to get GCC (3.3.6-m68hc1x-20060122) to automatically optimize out the redundant stack operations?
gcc will always emit the assembly instructions you tell it to emit. So instead of explicitly writing code to load registers with the value you want to manipulate, you instead want to tell gcc to do this on your behalf. You can do this with register constraints.
Unfortunately the 6811 code generator doesn't seem to be a standard part of gcc --- I don't spot the documentation in the manual. So I can't point you at platform-specific bit of the docs. But the generic bit you need to read is here: http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/Extended-Asm.html#Extended-Asm
The syntax is freaky, but the summary is:
asm("instructions" : outputs : inputs);
...where inputs and outputs are lists of constraints, which tell gcc what value to put where. The classic example is:
asm("fsinx %1,%0" : "=f" (result) : "f" (angle));
f indicates that the named value needs to go into a floating point register; = indicates it's an output; then the names of the registers are substituted into the instruction.
So, you'll probably want something like this:
asm("b" #op " " #offset ",%0 " #mask : "=Z" (i) : "0" (i));
...where i is a variable containing the value you want to modify. Z you'll need to look up in the 6811 gcc docs --- it's a constraint which represents a register which is valid for the asm instruction which is being generated. The 0 indicates that the input shares a register with output 0, and is used for read/write values.
Because you've told gcc what register you want i to be, it can integrate this knowledge into its register allocator and find the least-cost way to get i where you need it with the least amount of code. (Sometimes no additional code.)
gcc inline assembly is deeply contorted and weird, but pretty powerful. It's worth spending some time to thoroughly understand the constraint system to get the best use out of it.
(Incidentally, I don't know 6811 code, but have you forgotten to put the result of the op somewhere? I'd expect to see an stx to match the ldx.)
Update: Oh, I see what bset is doing now --- it's writing the result back to a memory location, right? That's still doable but it's a bit more painful. You need to tell gcc that you're modifying that memory location, so that it knows not to rely on any cached value. You'll need to have an output parameter with constraint m which represents that location. Check the docs.

Resources