Reverse engineering! :)

(previously 'DEVELOPER') Private forum for registered community members. To register, please visit www.prison-architect.com/register.

Moderator: NBJeff

User avatar
gsuberland
level2
level2
Posts: 161
Joined: Wed Sep 26, 2012 7:29 pm
Location: United Kingdom
Contact:

Reverse engineering! :)

Postby gsuberland » Sun Sep 30, 2012 12:01 pm

I've been digging into PA's memory to do some reverse engineering, for some bolt-on tool ideas I've had. The ultimate goal is to have a set of debug options external to the game program, so you can really dig into it and reset all sorts of actor data and game state data.

Here's what I have so far, with uninteresting unknown values removed, and some of the more interesting unknown fields left in.

Code: Select all

PrisonerStruct [size=488]:

+0008 = DWORD UnknownDword1
+000C = DWORD UnknownDword2
+0010 = DWORD ID_u
+0014 = DWORD ID_i
+0018 = DWORD EntityType (?)
+001C = DWORD SubType
+0020 = float Position_X
+0024 = float Position_Y
+0028 = float Or_X // rotation x: -1.0 = lean left, 0.0 = look straight ahead, +1.0 = lean right
+002C = float Or_Y // rotation y: 0 = face forwards, -1.0 = face backwards. large values (5, -5) make handcuffs appear in funny places.
+0038 = float UnknownFloat1
+003C = float Damage // 0.0 = healthy, 1.0 = dead
+0044 = void* UnknownPtr1
+0048 = void* UnknownPtr2
+004C = void* UnknownPtr3
+0050 = void* UnknownPtr4
+0060 = DWORD UnknownDword3
+009C = void* PtrToStartOfList
+00B0 = float NextPosition_X // this is a guess - the values are almost identical to Position X/Y
+00B4 = float NextPosition_Y // just have to assume that this is their position on the next frame / waypoint?
+00BC = DWORD UnknownID_u
+00C0 = DWORD UnknwonID_i
+00E0 = float UnknownFloat2
+00EC = float Destination_X
+00F0 = float Destination_Y
+00FC = float Velocity_X
+0100 = float Velocity_Y
+0110 = DWORD Cell_u
+0114 = DWORD Cell_i
+0134 = float UnknownFloat3
+0144 = char[16] Forename
+0154 = DWORD ForenameLength
+0158 = DWORD ForenameLengthMax
+0160 = char[16] Surname
+0170 = DWORD SurnameLength
+0174 = DWORD SurnameLengthMax
+0178 = float Age
+017C = DWORD UnknownDword4
+0180 = DWORD UnknownDword5
+0184 = DWORD UnknownDword6
+018C = float GangTimer
+0190 = DWORD GangID
+019C = DWORD PrisonerNeedCount
+01A0 = PrisonerNeedStruct** NeedsList // Pointer to a list of PrisonerNeedStruct entries
+01A8 = float UnknownFloat5
+01C4 = DWORD UnknownDword7
+01C8 = DWORD UnknownDword8


The NeedsList entry is a pointer to an array of PrisonerNeedStruct entries, which describe the prisoner's needs. From what I can work out, ActionPoint is the level when the need becomes immediate, e.g. "I have to go to the toilet". Charge is the current level that this prisoner is currently at, for this need. TimeToAction is the amount of time before Charge = ActionPoint, so I guess the rate is deduced from this. Not exactly sure how TimeToFailure works, but it looks like the amount of time before the prisoner gets angry about not having fulfilled this need.

Code: Select all

PrisonerNeedStruct [size=96]:

+0004 DWORD UnknownDword1
+0008 DWORD UnknownDword2
+000C DWORD Id_u
+0010 DWORD Id_i
+0014 DWORD NeedType // see PrisonerNeedTypes
+0018 float ActionPoint
+001C float TimeToAction
+0020 float TimeToFailure
+0024 float Charge



Here's the PrisonerNeedType values (they're DWORDs):

Code: Select all

bladder = 1
bowels = 2
sleep = 3
food = 4
hygiene = 5
comfort = 6
excercise = 7
defense = 8
freedom = 9
family = 10
recreation = 11
[dev]weapon = 12


I've not got fully reliable pointer paths to the prisoner array yet, but I'm working on it. Right now I'm using some code injection techniques to leak the base pointer, which is pretty reliable.

Hopefully this will help someone else if they're creating similar tools :)
Last edited by gsuberland on Mon Oct 01, 2012 8:50 pm, edited 5 times in total.
ppiixx
level0
Posts: 5
Joined: Tue Nov 29, 2011 11:40 pm
Location: United Kingdom

Postby ppiixx » Sun Sep 30, 2012 12:03 pm

I take it you have looked at the save file format as that should give some clues to the structs
User avatar
gsuberland
level2
level2
Posts: 161
Joined: Wed Sep 26, 2012 7:29 pm
Location: United Kingdom
Contact:

Postby gsuberland » Sun Sep 30, 2012 12:07 pm

ppiixx wrote:I take it you have looked at the save file format as that should give some clues to the structs


Yeah, that's been my main source of information. Some of the stuff seems to be internal, though, because it doesn't appear in the save file. I've figured some of it out, but a lot of it is guesswork.
In prison, you get your own toilet. At work, you have to share.
User avatar
gsuberland
level2
level2
Posts: 161
Joined: Wed Sep 26, 2012 7:29 pm
Location: United Kingdom
Contact:

Postby gsuberland » Sun Sep 30, 2012 1:07 pm

Of course, one of the benefits of this knowledge is that I can do silly stuff like this:

Image
In prison, you get your own toilet. At work, you have to share.
User avatar
a__gun
level3
level3
Posts: 281
Joined: Wed Sep 26, 2012 4:16 pm
Location: UK

Postby a__gun » Sun Sep 30, 2012 1:29 pm

lol. A bit too much time on your hands maybe :p
User avatar
gsuberland
level2
level2
Posts: 161
Joined: Wed Sep 26, 2012 7:29 pm
Location: United Kingdom
Contact:

Postby gsuberland » Sun Sep 30, 2012 1:52 pm

a__gun wrote:lol. A bit too much time on your hands maybe :p


What else am I supposed to do with my weekend!? ;)
In prison, you get your own toilet. At work, you have to share.
User avatar
a__gun
level3
level3
Posts: 281
Joined: Wed Sep 26, 2012 4:16 pm
Location: UK

Postby a__gun » Sun Sep 30, 2012 2:10 pm

Why, sunday lunch of course!
zeroZshadow
level1
level1
Posts: 23
Joined: Sun Jul 03, 2005 11:28 am

Postby zeroZshadow » Sun Sep 30, 2012 3:34 pm

Im missing a few types like locked, attacktimer, aisettarget, equipment and equipment u/i in that list
User avatar
gsuberland
level2
level2
Posts: 161
Joined: Wed Sep 26, 2012 7:29 pm
Location: United Kingdom
Contact:

Postby gsuberland » Sun Sep 30, 2012 9:23 pm

zeroZshadow wrote:Im missing a few types like locked, attacktimer, aisettarget, equipment and equipment u/i in that list


The equipment stuff shouldn't be hard to find. There are quite a few reliable pointers in the struct, so I should imagine it'd be easy to find a prisoner with equipment and reverse engineer how that works.

Only bit I can't figure out is how the memory is allocated for the list. There seems to be a set of 3 or 4 different lists, so it's probably a dynamic list with blocks generated by malloc. I'm having some trouble finding any memory regions that directly correlate to those block pointers - maybe it's not as trivial as I thought. Right now I'm just cheating the system a bit by injecting into some code that regularly touches all prisoner structs, so I can harvest the pointers from there.
In prison, you get your own toilet. At work, you have to share.
zeroZshadow
level1
level1
Posts: 23
Joined: Sun Jul 03, 2005 11:28 am

Postby zeroZshadow » Sun Sep 30, 2012 9:33 pm

Since it has a pointer to the start of the list, might it not just be a linked list? so there should be a pointer to the NEXT prisoner struct somewhere in there?
User avatar
gsuberland
level2
level2
Posts: 161
Joined: Wed Sep 26, 2012 7:29 pm
Location: United Kingdom
Contact:

Postby gsuberland » Sun Sep 30, 2012 9:39 pm

zeroZshadow wrote:Since it has a pointer to the start of the list, might it not just be a linked list? so there should be a pointer to the NEXT prisoner struct somewhere in there?


That pointer only goes to the start of that specific list. I checked the first and last entries in that block for pointers to other entries elsewhere - no such luck :/
In prison, you get your own toilet. At work, you have to share.
User avatar
scottystreet
level1
level1
Posts: 41
Joined: Fri Jan 01, 2010 6:15 pm
Contact:

Postby scottystreet » Mon Oct 01, 2012 8:27 pm

Nice to see you've added your findings to the Wiki...
What I'm struggling to work out in terms of Modding capabilities is where the 'incoming call' dialog files are stored. They're referenced in the Deathrow Lua files as Game.AdviserSay, but I can't find them anywhere. Managed to find out most other stuff I needed, but not this :(

EDIT: And on the note of a prisoners needs, they are found in the .prison save files. Here's an example of the properties of a prisoner with a section for needs:

Code: Select all

    BEGIN "[i 63]"     
        Id.i                 63 
        Id.u                 42043 
        Type                 Prisoner 
        SubType              2 
        Pos.x                67.4187 
        Pos.y                47.3875 
        Walls.y              -1.00000 
        Loaded               true 
        CarrierId.i          112 
        CarrierId.u          45533 
        Cell.i               5 
        Cell.u               45458 
        Timer                2.09589 
        Gang.id              1 
        Gang.timer           1.45132 
        BEGIN Needs     
            BEGIN Needs     
                Size                 10 
                BEGIN "[i 0]"      id.i 0  id.u 237470  Type Bladder  ActionPoint 36.0000  TimeToAction 600.000  TimeToFailure 720.000  Charge 4.90105  END
                BEGIN "[i 1]"      id.i 1  id.u 237471  Type Bowels  ActionPoint 53.0000  TimeToAction 600.000  TimeToFailure 1440.00  Charge 49.3315  END
                BEGIN "[i 2]"      id.i 2  id.u 237472  Type Sleep  ActionPoint 41.0000  TimeToAction 1440.00  TimeToFailure 1440.00  Charge 66.7322  END
                BEGIN "[i 3]"      id.i 3  id.u 237473  Type Food  ActionPoint 33.0000  TimeToAction 960.000  TimeToFailure 1440.00  Charge 17.1605  END
                BEGIN "[i 4]"      id.i 4  id.u 237474  Type Hygiene  ActionPoint 65.0000  TimeToAction 1440.00  TimeToFailure 1440.00  Charge 70.5140  END
                BEGIN "[i 5]"      id.i 5  id.u 237475  Type Exercise  ActionPoint 59.0000  TimeToAction 1440.00  TimeToFailure 1440.00  Charge 28.9908  END
                BEGIN "[i 6]"      id.i 6  id.u 237476  Type Freedom  ActionPoint 41.0000  TimeToAction -1440.00  TimeToFailure -1440.00  Charge 13.6565  END
                BEGIN "[i 7]"      id.i 7  id.u 237477  Type Family  ActionPoint 45.0000  TimeToAction 1440.00  TimeToFailure 1440.00  Charge 100.000  END
                BEGIN "[i 8]"      id.i 8  id.u 237478  Type Recreation  ActionPoint 63.0000  TimeToAction 1440.00  TimeToFailure 1440.00  Charge 100.000  END
                BEGIN "[i 9]"      id.i 9  id.u 237479  Type [dev]Weapon  ActionPoint 100.000  END
            END
        END
    END


But I guess you already know that ;)
User avatar
gsuberland
level2
level2
Posts: 161
Joined: Wed Sep 26, 2012 7:29 pm
Location: United Kingdom
Contact:

Postby gsuberland » Mon Oct 01, 2012 9:23 pm

Found two nice reliable pointers:

Current time (32-bit float)

Code: Select all

[pa.exe+0x002e7de8] +0x4 +0x0 +0x0 +0x20 +0x8


The current time is measured in seconds. You can modify it to alter the clock and time of day. Skipping ahead causes some glitches, as does skipping back, but you can use it to get more or less prisoners. Downside is it messes up some objective timer stuff too.

Prisoner Count (32-bit signed integer, read only)

Code: Select all

[pa.exe+0x002e8de8] +0x04 +0x78 +0x64 +0x20 +0x1f8


This is just the calculated value - you can't change it. Useful for digging out prisoner structs - you know when you've got them all! :)
zeroZshadow
level1
level1
Posts: 23
Joined: Sun Jul 03, 2005 11:28 am

Postby zeroZshadow » Mon Oct 01, 2012 9:26 pm

Did you try decompressing the exe with UPX and running it through IDA?
User avatar
gsuberland
level2
level2
Posts: 161
Joined: Wed Sep 26, 2012 7:29 pm
Location: United Kingdom
Contact:

Postby gsuberland » Wed Oct 03, 2012 7:10 am

zeroZshadow wrote:Did you try decompressing the exe with UPX and running it through IDA?


Not got round to it. UPX is a pain, due to having to re-generate the IAT.

Does UPX still have the "un-UPX" option?
In prison, you get your own toilet. At work, you have to share.

Return to “Community Members”

Who is online

Users browsing this forum: No registered users and 21 guests