How PSO games calculate SectionID

MagicLuthee

Member
I'm on a quest to find out how PSO games calculate Section ID.

First step : PSO PC (Done)
Second step : PSOGC (In progress)
Third step : PSOBB

PSO PC Dynamic Analysis with x32dbg (Commented)
Code:
00461E20 | 56                       | push esi                             | Push esi onto the stack
00461E21 | 8B7424 08                | mov esi,dword ptr ss:[esp+0x8]       | Place player name string into ESI
00461E25 | 33C0                     | xor eax,eax                          | Set EAX to 0
00461E27 | 33D2                     | xor edx,edx                          | Set EDX to 0
00461E29 | 8A0E                     | mov cl,byte ptr ds:[esi]             | [A] Place byte value found at the address of ESI into CL (the current character)
00461E2B | 84C9                     | test cl,cl                           | --
00461E2D | 74 0C                    | je pso.461E3B                        | Jump to [B] if null character found (if CL == 0)
00461E2F | 0FBEC9                   | movsx ecx,cl                         | Sign-extend CL (make CL 32-bit, preserve sign) move result to ECX
00461E32 | 03C1                     | add eax,ecx                          | Add ECX (value of letter at current pointer) to EAX
00461E34 | 42                       | inc edx                              | Increment EDX by 1 (EDX counts letters in string)
00461E35 | 46                       | inc esi                              | Increment ESI by 1 (ESI points current character in string)
00461E36 | 83FA 0C                  | cmp edx,0xC                          | --
00461E39 | 7C EE                    | jl pso.461E29                        | Jump to [A] if letter count < 12
00461E3B | 99                       | cdq                                  | [B] Sign extend EAX into EDX (for later)
00461E3C | B9 0A000000              | mov ecx,0xA                          | Place decimal number 10 in ecx
00461E41 | 5E                       | pop esi                              | Place last value that was added to the stack (back at line 1) into ESI and remove it from Stack
00461E42 | F7F9                     | idiv ecx                             | Do signed 32-bit division : EAX / ECX and place quotient in EAX, remainder in EDX
00461E44 | 8BC2                     | mov eax,edx                          | Place remainder into EAX
00461E46 | 85C0                     | test eax,eax                         | --
00461E48 | 7C 04                    | jl pso.461E4E                        | Jump to [C] if EAX Negative (Special use of JL with TEST EAX EAX)
00461E4A | 3BC1                     | cmp eax,ecx                          | --
00461E4C | 7C 02                    | jl pso.461E50                        | Jump to [D] if EAX > 9
00461E4E | 33C0                     | xor eax,eax                          | [C] Zero out EAX
00461E50 | C3                       | ret                                  | [D] Return

Code:
00502140 | 8B4424 04                | mov eax,dword ptr ss:[esp+0x4]                                  | Move result of previous function into EAX
00502144 | 8B0485 38C66900          | mov eax,dword ptr ds:[eax*4+0x69C638]                           | Get Section ID from table (which starts at 0x69C638)
0050214B | C3                       | ret                                                             | Return Section ID
 
Last edited:
PSO PC Static Analysis with Ghidra
Code:
004623e0 56              PUSH       ESI
004623e1 8b 74 24 08     MOV        ESI,dword ptr [ESP + param_1]
004623e5 33 c0           XOR        EAX,EAX
004623e7 33 d2           XOR        EDX,EDX
                             LAB_004623e9                                    XREF[1]:     004623f9(j)
004623e9 8a 0e           MOV        CL,byte ptr [ESI]
004623eb 84 c9           TEST       CL,CL
004623ed 74 0c           JZ         LAB_004623fb
004623ef 0f be c9        MOVSX      ECX,CL
004623f2 03 c1           ADD        EAX,ECX
004623f4 42              INC        EDX
004623f5 46              INC        ESI
004623f6 83 fa 0c        CMP        EDX,0xc
004623f9 7c ee           JL         LAB_004623e9
                             LAB_004623fb                                    XREF[1]:     004623ed(j)
004623fb 99              CDQ
004623fc b9 0a 00        MOV        ECX,0xa
                 00 00
00462401 5e              POP        ESI
00462402 f7 f9           IDIV       ECX
00462404 8b c2           MOV        EAX,EDX
00462406 85 c0           TEST       EAX,EAX
00462408 7c 04           JL         LAB_0046240e
0046240a 3b c1           CMP        EAX,ECX
0046240c 7c 02           JL         LAB_00462410
                             LAB_0046240e                                    XREF[1]:     00462408(j)
0046240e 33 c0           XOR        EAX,EAX
                             LAB_00462410                                    XREF[1]:     0046240c(j)
00462410 c3              RET

Code:
00503830 8b 44 24 04     MOV        EAX,dword ptr [ESP + param_1]
00503834 8b 04 85        MOV        EAX,dword ptr [EAX*0x4 + PTR_u_VIRIDIA_006a0478] = 006a0550
78 04 6a 00
0050383b c3              RET


PSO PC C Code Equivalent

Code:
int compute(char *string)
{
  int counter;
  int sum;

  sum = 0;
  counter = 0;
  do {
    if (*string == '\0') break;
    sum = sum + *string;
    counter = counter + 1;
    string = string + 1;
  } while (counter < 12);
  sum = sum % 10;
  if ((sum < 0) || (9 < sum)) {
    sum = 0;
  }
  return sum;
}

Code:
wchar_t * getSectionID(int index)
{
    wchar_t * viridia = L"VIRIDIA\0";
    wchar_t * greenill = L"GREENNILL\0";
    wchar_t * skyly = L"SKYLY\0";
    wchar_t * bluefull = L"BLUEFULL\0";
    wchar_t * purplenum = L"PURPLENUM\0";
    wchar_t * pinkal = L"PINKAL\0";
    wchar_t * redria = L"REDRIA\0";
    wchar_t * oran = L"ORAN\0";
    wchar_t * yellowboze = L"YELLOWBOZE\0";
    wchar_t * whitill = L"WHITILL\0";
    wchar_t ** ptr_viridia;
    ptr_viridia = &viridia;
    return ptr_viridia[index];
}
 
Last edited:
Hey I decided to try and take a look at PSO GC (Plus) game code. I'll update this post with my findings.

PSO GC Static Analysis with Ghidra (Gecko PowerPC CPU Instructions)
PTR_s_VIRIDIA_804a6ee0 XREF[1]: FUN_801329fc:80132a08(R) 804a6ee0 80 43 e9 f0 addr s_VIRIDIA_8043e9f0 = "VIRIDIA" 804a6ee4 80 43 e9 f8 addr s_GREENILL_8043e9f8 = "GREENILL" 804a6ee8 80 43 ea 04 addr s_SKYLY_8043ea04 = "SKYLY" 804a6eec 80 43 ea 0c addr s_BLUEFULL_8043ea0c = "BLUEFULL" 804a6ef0 80 43 ea 18 addr s_PURPLENUM_8043ea18 = "PURPLENUM" 804a6ef4 80 43 ea 24 addr s_PINKAL_8043ea24 = "PINKAL" 804a6ef8 80 43 ea 2c addr s_REDRIA_8043ea2c = "REDRIA" 804a6efc 80 43 ea 34 addr s_ORAN_8043ea34 = "ORAN" 804a6f00 80 43 ea 3c addr s_YELLOWBOZE_8043ea3c = "YELLOWBOZE" 804a6f04 80 43 ea 48 addr s_WHITILL_8043ea48 = "WHITILL" 804a6f08 80 43 ea 50 addr s_???????_8043ea50 = "???????"
Comment : I was curious about the order in which they were laid out in the GC version code...

************************************************************** * FUNCTION * ************************************************************** int __stdcall FUN_8028dc74(char * param_1) assume GQR0 = 0x0 assume GQR1 = 0x8040804 assume r13 = 0x805da600 assume r2 = 0x805dfd00 int r3:4 <RETURN> char * r3:4 param_1 FUN_8028dc74 XREF[1]: FUN_8029737c:802973e8(c) 8028dc74 38 a0 00 00 li r5,0x0 8028dc78 38 c0 00 00 li r6,0x0 8028dc7c 48 00 00 14 b LAB_8028dc90 LAB_8028dc80 XREF[1]: 8028dca0(j) 8028dc80 7c 80 07 74 extsb r0,r4 8028dc84 38 63 00 01 addi param_1,param_1,0x1 8028dc88 7c a5 02 14 add r5,r5,r0 8028dc8c 38 c6 00 01 addi r6,r6,0x1 LAB_8028dc90 XREF[1]: 8028dc7c(j) 8028dc90 2c 06 00 0c cmpwi r6,0xc 8028dc94 40 80 00 10 bge LAB_8028dca4 8028dc98 88 83 00 00 lbz r4,0x0(param_1) 8028dc9c 7c 80 07 75 extsb. r0,r4 8028dca0 40 82 ff e0 bne LAB_8028dc80 LAB_8028dca4 XREF[1]: 8028dc94(j) 8028dca4 38 60 00 0a li param_1,0xa 8028dca8 7c 05 1b d6 divw r0,r5,param_1 8028dcac 7c 00 19 d6 mullw r0,r0,param_1 8028dcb0 7c a0 28 51 subf. r5,r0,r5 8028dcb4 41 80 00 0c blt LAB_8028dcc0 8028dcb8 2c 05 00 0a cmpwi r5,0xa 8028dcbc 41 80 00 08 blt LAB_8028dcc4 LAB_8028dcc0 XREF[1]: 8028dcb4(j) 8028dcc0 38 a0 00 00 li r5,0x0 LAB_8028dcc4 XREF[1]: 8028dcbc(j) 8028dcc4 7c a3 2b 78 or param_1,r5,r5 8028dcc8 4e 80 00 20 blr
Comment : This looks like the name computation function, I found this function by going through all occurences of a divw instruction...


PSO GC C Code Equivalent
int FUN_8028dc74(char *param_1) { char cVar1; int iVar2; int iVar3; iVar2 = 0; iVar3 = 0; while( true ) { if (0xb < iVar3) break; cVar1 = *param_1; if (cVar1 == '\0') break; param_1 = param_1 + 1; iVar2 = iVar2 + cVar1; iVar3 = iVar3 + 1; } iVar2 = iVar2 % 10; if ((iVar2 < 0) || (9 < iVar2)) { iVar2 = 0; } return iVar2; }
 
Last edited:
Back
Top