Jump to content

GTA LCS/VCS research project


fastman92

Recommended Posts

In this topic I will post about what's already known about LCS/VCS.

Topic will be updated as the research is going on.

 

I understood the SCM format of LCS/VCS SCM and recognized most of the LCS & VCS SCM commands.

I wrote a simple compiler in C++ for SCM in 3 days.

 

I made a stripped main.scm for LCS and VCS.

 

Here's how player looks in LCS with my stripped SCM:

27a2d1312872643.jpg

 

Test of stripped SCM for VCS:

61f7bc312455555.jpg

My testing script gets 3D coords of player, converts them to 2D screen coords and displays a text 'M_OVER', which i have edited in english.gxt

 

CLEO library for LCS/VCS?

That would be a great addition for these games, I think.

It would require learning how to develop for PS2.

Edited by fastman92
Link to comment
Share on other sites

Interesting... I have VCS on PS2, but I can't mod the PS2 because it's my cousin's :( . BTW this is awesome! Keep up the good work!

Link to comment
Share on other sites

How to fix $gp based offsets in MIPS executable?

Some time ago during analysis of GTA LCS executable I found a code like this:

110418312927545.jpg

 

 

 

 

 

 

 

 

 

.text:00109E0C 080 move $a0, $s2 # file.text:00109E10 080 jal CFileMgr__Read # Offset is 8 from begginng now, read MAIN section now.text:00109E14 080 lw $a2, 0x2D34($gp) # num
You see, the data (size of MAIN section read from main.scm) is being loaded from address pointed by a value of $gp + immediate value 0x2D34

 

$gp is the name of MIPS register that points to the global area.

 

In other worlds the address where the value is loaded from = value of $gp + 0x02D34.

From how $gp is used it can be said that a value of $gp is constant - never changes during execution of game code.

 

 

But because $gp is nowhere declared in a function, IDA Pro doesn't know the value of $gp and won't create a reference to memory value.

First of all, we need to know what is the value of $gp

 

In functions CTheScripts::Init $gp is already set up.

We know that CTheScripts::Init must have been called by some function which has yet been called by another higher function.

We can go to reference of our function and see if $gp is set up there.

Actually the function in which $gp is set up is named a start

It's entry point of executable.

24b943312932261.jpg

We see, this code sets all registers to zero.

 

But still zero isn't going to be a value of $gp.

We can look the code below:

8a76e4312933017.jpg

 

.text:001C6C04 000 la $a0, asc_3D6EF0 # "\nÎ#=".text:001C6C08 000 li $a1, 0x1FE0000.text:001C6C0C 000 li $a2, 0x20000.text:001C6C10 000 la $a3, dword_410180.text:001C6C14 000 la $t0, loc_1C6CA8.text:001C6C18 000 move $gp, $a0
We can clearly see the instruction

 

la $a0, asc_3D6EF0 # "\nÎ#="
$a0 = 0x3D6EF0

Then what happens is $gp gets a value of $a0, which is 0x3D6EF0

 

Let's go back to CTheScripts::Init

 

.text:00109E10 080 jal CFileMgr__Read # Offset is 8 from begginng now, read MAIN section now.text:00109E14 080 lw $a2, 0x2D34($gp) # num
In IDA Pro you can press Ctrl + R on operand and set the base address which is 0x3D6EF0 in this case.

Then what we get is

 

.text:00109E14 080 lw $a2, (_ZN11CTheScripts14MainScriptSizeE - asc_3D6EF0)($gp) # num
But since $gp value is not meaningful, we should better have no reference to asc_3D6EF0 here.

Ctrl + R, check the Treat the base address as a plain number.

 

.text:00109E14 080 lw $a2, (_ZN11CTheScripts14MainScriptSizeE - 0x3D6EF0)($gp) # num
Now it's better.

 

But there are thousand of $gp references, it would be a hell work to search for $gp register references and set them up manually by hand.

IDA Pro is very interactive tool, when manual analysis of code fails because of the amount of ($gp) references, the IDC/Python may be written to automate the process.

 

I wrote a simple IDC script to fix the $gp references in MIPS executables.

Link to this script: http://pastebin.com/c3Zu4Rix

 

 

How to mark data as strings in range of addresses?

A lot of times you may find data that must be strings, but since they're not referenced by any instruction, IDA Pro won't mark them as string values.

 

Beginning:

0ba489312958507.jpg

And this is where the last string may be found:

40e219312959351.jpg

 

You can see on the screenshot, one string coming after another.

You could press A in beginning of each string.

But if strings are in a specified range of addresses and they're many, it's more efficient to use a script that will detect and mark strings automatically.

All you need is to set up firstAddress and endAddress in a script.

Link to script: http://pastebin.com/jeVjGZNe

Edited by fastman92
Link to comment
Share on other sites

Wow! That very interesting, are you have any idb base of vcs_ps2? And I see you executable of lcs with name of many functions, can you say how to restore native function names?

 

P.S. Have you are skype?

Edited by mike43842
Link to comment
Share on other sites

I have manually analyzed GTA LCS and VCS executable files in IDA Pro in comparison to GTA III, VC, SA for Android.

The thing is GTA III, VC, SA for Android have original mangled names of functions and since I'm not new to reverse engineering, I could find equivalent functions in LCS and VCS.

As you may guess most of the functions have to be the same in LCS and VCS.

 

Have you done any software reverse engineering?

 

Btw, don't report my posts.

Edited by fastman92
Link to comment
Share on other sites

Unfortunately i'm not good in Reverse Engineering, but I learn MIPS and x86 asm, and try rewrite some functions in C++, I want transfer opcodes from vcs to SA and that why I'm interested in this post. Can you open your PM?

Edited by mike43842
Link to comment
Share on other sites

Nothing in PM.

 

Transferring opcodes is not possible in any other way than putting equivalent IDs in GTA SA game.

 

For example:

VCS:

 

00D9=2,store_car_char_is_in %1d% store_to %2d%
SA:

 

 

 

 

 

00D9=2,store_car_char_is_in %1d% store_to %2d%
You may want to learn ARM too. Once you grasp the concept of conditional execution, it's getting easier.

 

----------------------------------------

I decided to test opcodes:

 

0456:  0 044E:  0 1 0451:  0 350 60 0450:  0 5 5 0452:  0 0 0 0 128 0453:  0 0 0 0 0 
That's what I got:

c2d7fd313163002.jpg

 

----------------------------------------

GTA San Andreas.

 

I NOPPed instruction at 0x527972 (7 bytes), then I assigned a value of 1 to byte on address 0xB6EC20

 

This is what I've got:

1b2228313186068.jpg

 

You see me driving and breaking on street of LS.

Edited by fastman92
Link to comment
Share on other sites

Hmm. PS2 only scm? Or are you going to be working on PSP versions as well?

Link to comment
Share on other sites

Hmm. PS2 only scm? Or are you going to be working on PSP versions as well?

Is there PSP emulator for PC?

Edited by fastman92
Link to comment
Share on other sites

 

Hmm. PS2 only scm? Or are you going to be working on PSP versions as well?

Is there PSP emulator for PC?

 

http://www.ppsspp.org/
Link to comment
Share on other sites

If you need any help PSP version wise I can help. I have a PSP for testing, and I know some C++ and am learning reverse engineering ATM. Although I don't think I could be much help there, I could, at the least, test everything.

Link to comment
Share on other sites

Hmm. PS2 only scm? Or are you going to be working on PSP versions as well?

I looked into PSP version of VCS.

I'm not skilled enough to disassemble and reverse engineer it.

Link to comment
Share on other sites

Ah, well, I couldn't resist asking.. :p



Thanks for looking into it though!


Link to comment
Share on other sites

I found out what

 

627a42313632464.jpg

 

05AC and 05AD opcodes in LCS do.

 

Screenshot tells it.

 

I named it

 

SET_DESTINATION_COORDINATESCLEAR_DESTINATION_COORDINATES
If destination coordinates are set, an arrow will appear on screen pointed to destination coordinates.

 

It's 0x0378 and 0x0379 in VCS.

 

----------------------------------------

Part of my testing script for VCS main.txt:

 

 

:loopWAIT 0USE_TEXT_COMMANDS 10377: get_pad_state actionID 0 store_to 1@000F:   1@ > 0 // (int) var > num0022: goto_if_false @loop02EE: get_offset_from_char_in_world_coords $PLAYER_ACTOR offset 0.0 3.0 1.0 store_to 2@ 3@ 4@REQUEST_MODEL 99:checkIfModelLoadedWAIT 0HAS_MODEL_LOADED 99GOTO_IF_FALSE @checkIfModelLoadedGET_GROUND_Z_FOR_3D_COORD 2@ 3@ 4@ 4@003E: create_char 4 model 99 at 2@ 3@ 4@ store_to 5@ 015D: set_actor 5@ ped_stats_to 32MARK_MODEL_AS_NO_LONGER_NEEDED 99MARK_CHAR_AS_NO_LONGER_NEEDED 5@wait 1000GOTO @loop
It spawns a soldier that tries to beat me to the death.

 

0fc36f313641495.jpg

Edited by fastman92
Link to comment
Share on other sites

fastman92, can you show screen, in code of opcode 0378 in VCS, where are get using model arrow? I know this model is in GAME.dtz, but I can't find in .elf where are this model using, I tried find that at this opcode function but I find nothing.

 

P.S. sorry for my broken English.

Link to comment
Share on other sites

fastman92, can you show screen, in code of opcode 0378 in VCS, where are get using model arrow? I know this model is in GAME.dtz, but I can't find in .elf where are this model using, I tried find that at this opcode function but I find nothing.

 

P.S. sorry for my broken English.

Sorry, I don't know model is this.

I use a command to set the destination coordinates and it just works.

 

I have found a better R* name to these commands

 

 

.rodata:004B8190     aSetpointerarrow:.ascii "SetPointerArrow"<0>.rodata:004B81A0     aClearpointerarrow:.ascii "ClearPointerArrow"<0>
Edited by fastman92
Link to comment
Share on other sites

While building my database I noticed this GTA VC opcode:

 

 

045F: set_all_occupants_of_car_leave_car 0@ 4
In decompiled main.scm:

 

045F: set_all_occupants_of_car_leave_car 0@ 4 00D6: if 0038:   $6846 == 0 004D: goto_if_false @FIRETRU_6945 03C4: display_onscreen_counter_with_string $6847 type 0 gxt 'F_EXTIN'  // FIRES:0004: $6846 = 1 
More interestingly I knew this opcode has only one parameter in different games.

 

I checked how the second parameter of this command in VC is used:

 

      CRunningScript__CollectParameters(this, &this->_ip, 1u);      v31 = CPool_CVehicle__atHandle(VehiclePool, opcodeParams[0]);      AllExitVehicle(v31);      return 0;
But instead, I found that the game collects only one parameter.

 

http://gtag.gtagaming.com/opcode-database/opcode/045F/

 

Of course, GTAG tells it has 2 parameters.

 

I looked into VC's main.scm and located where the 045F opcode is and what comes the next.

 

 

5F 04 03 00 00 04 04 D6 00 04 00
5F 04 - 044F: opcode

03 - local variable, value 00 00 what means 0@

 

Then the next command is executed:

 

04 04
0x0404

 

http://gtag.gtagaming.com/opcode-database/opcode/0404/

 

which is REGISTER_FIRE_EXTINGUISHED.

 

I made appropriate changes to my database, generated new INI for Sanny Builder and decompiled VC's main.scm again.

 

045F: set_all_occupants_of_car_leave_car 0@ 0404: register_fire_extinguished 00D6: if 0038:   $6846 == 0 004D: goto_if_false @FIRETRU_6945 03C4: display_onscreen_counter_with_string $6847 type 0 gxt 'F_EXTIN'  // FIRES:
Now the SB's output is much better.
Link to comment
Share on other sites

I'll have to say, congratz. It is not often that someone finds a way to mod LCS/VCS!

  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...

I discovered why Streaming memory fix 2.0 by Alexander Blade is bound to crash the game after ~10 minutes of playing.

 

Default limit of streamed vehicles is 22. Alexander Blade's plugin increases it.

Default limit of number of members per car group (cargrp.dat stuff) is 23.

 

The limit of streamed vehicles has to be lower than a limit of number of members per loaded car group.

Otherwise the game will always find there are 23 vehicles loaded and since it's lower or equal to limit of streamed vehicles, it will load them infinitely not freeing a memory.

The game has allocation limit specified by a number of elements.

Edited by fastman92
  • Like 2
Link to comment
Share on other sites

How to rename a list of functions from old names to new names?

 

Sometimes there comes a time when in IDA Pro we need to rename quite a lot functions and we also have a list of new names that should be assigned.

 

IDC scripting comes in handy.

I wrote a script to assign new names to functions by first locating them with old names.

 

http://pastebin.com/kkWqJwKs

 

You need to define an old name and a new name as follows:

 

 

 

 

	list.AddMember("_sub_550170", "png_set_unknown_chunks");	list.AddMember("$CPool_CPtrNodeSingle__constructor", "png_set_unknown_chunk_location");
How to get values from li $at, float in MIPS executable?

 

While disassembling a MIPS executable I noticed that a part of float values would appear as integer value instead.

 

f806b9319154770.jpg

 

Since it's impossible to turn these integer values into float values in IDA Pro, I wrote a Python script that puts a comment that tells a float value used in the instruction.

 

6fe9b9319155172.jpg

As shown on the screenshot, comment with a value was inserted.

 

This script will not override existing user comments.

 

Link to script: http://pastebin.com/GEk306DW

Edited by fastman92
Link to comment
Share on other sites

  • 2 years later...

Slightly off OP's topic but, do any of you guys know if it is at all possible to change the size of explosions or flames caused by grenades and molotovs respectively. It'd be pretty dope if we can make the explosions 10x larger i mean think about all the chaos xD.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • 1 User Currently Viewing
    0 members, 0 Anonymous, 1 Guest

×
×
  • Create New...

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.