If you're having problems compiling GBA4DS, you'll need to edit the make file in bootstub to reflect the change to arm-none-eabi*
You will also need a copy of the R4 menu in the root dir of your source.
Monday, March 11, 2013
Sunday, March 3, 2013
Saturday, February 9, 2013
Decompilation example
Quick example of how well the plugin works
void RestoreHealth(){ //Original function
u16* curHealth=(u16*)0x3001310;
u16* maxHealth=(u16*)0x3001312;
unsigned short val=*maxHealth-*curHealth;
*curHealth+=val;
}
Here's the assembeled copy
EXPORT RestoreHealth
RestoreHealth
var_8 = -8
var_4 = -4
SUB SP, SP, #0x10
LDR R3, =0x3001310
STR R3, [SP,#0x10+var_4]
LDR R3, =0x3001312
STR R3, [SP,#0x10+var_8]
LDR R3, [SP,#0x10+var_8]
LDRH R1, [R3]
LDR R3, [SP,#0x10+var_4]
LDRH R2, [R3]
MOV R3, SP
ADDS R3, #6
SUBS R2, R1, R2
STRH R2, [R3]
LDR R3, [SP,#0x10+var_4]
LDRH R2, [R3]
MOV R3, SP
ADDS R3, #6
LDRH R3, [R3]
ADDS R3, R2, R3
LSLS R3, R3, #0x10
LSRS R2, R3, #0x10
LDR R3, [SP,#0x10+var_4]
STRH R2, [R3]
ADD SP, SP, #0x10
BX LR
; End of function RestoreHealth
; ---------------------------------------------------------------------------
ALIGN 0x10
dword_8000320 DCD 0x3001310 ; DATA XREF: RestoreHealth+2 r
dword_8000324 DCD 0x3001312 ; DATA XREF: RestoreHealth+6 r
And here's the decompiled version!
; ---------------------------------------------------------------------------
EXPORT RestoreHealth
RestoreHealth
void RestoreHealth() { // framesize 0x10
(unsigned long)SP+0xC = 0x3001310;
(unsigned long)SP+8 = 0x3001312;
(unsigned short)SP+6 = word<(unsigned long)SP+8> - word<(unsigned long)SP+0xC>;
word<(unsigned long)SP+0xC> = word<(unsigned long)SP+0xC> + (unsigned short)SP+6 & 0xFFFF;
return void
}
; ---------------------------------------------------------------------------
Decompiler update
Greetings!
There is now a repository for the decompiler!
http://code.google.com/p/arm-thumb-decompiler-plugin/
If you wish to be a committer please e-mail myself or normmatt.
Helpers are welcome! :)
Here's the current r11 binaries.
https://dl.dropbox.com/u/12510094/NEVERDELETE/decompilerr11.zip
Romhacking update soon, maybe today.
Best jump table detection!
There is now a repository for the decompiler!
http://code.google.com/p/arm-thumb-decompiler-plugin/
If you wish to be a committer please e-mail myself or normmatt.
Helpers are welcome! :)
Here's the current r11 binaries.
https://dl.dropbox.com/u/12510094/NEVERDELETE/decompilerr11.zip
Romhacking update soon, maybe today.
Best jump table detection!
Monday, February 4, 2013
Fixed a bug in the decompiler
Hello!
Last release of the decompiler could only detect switches in the following format.
80 00 LSL R0, R0, #2
02 49 LDR R1, =off_83C173C
40 18 ADD R0, R0, R1
00 68 LDR R0, [R0]
87 46 MOV PC, R0
I successfully have it reading switches from r1, and will be advancing it to switches with any registers.
I also have to look into getting default case switches to work.
Expect a release soon!
Last release of the decompiler could only detect switches in the following format.
80 00 LSL R0, R0, #2
02 49 LDR R1, =off_83C173C
40 18 ADD R0, R0, R1
00 68 LDR R0, [R0]
87 46 MOV PC, R0
I successfully have it reading switches from r1, and will be advancing it to switches with any registers.
I also have to look into getting default case switches to work.
Expect a release soon!
Sunday, February 3, 2013
Thumb Decompiler plugin
Hello!
Here's the first release of that decompiler I've been talking about. It's a huge help, thank you Ludde.
Updates will come and I'll eventually get a googlecode for it.
Little tutorial on setup
Hello! This is a quick tutorial on how to use the updated version of Luddes, thumdecompiler.
Easy to use, with powerful results. That man is a genius. Anyway, it's helped me a lot and I hope it can help with malicious, or bad code or debug something that got compiled wrong
https://dl.dropbox.com/u/12510094/NEVERDELETE/IDATHUMBDECOMPILER.zip Plug in link
https://dl.dropbox.com/u/12510094/NEVERDELETE/thumb.zip Source code.
Here's the first release of that decompiler I've been talking about. It's a huge help, thank you Ludde.
Updates will come and I'll eventually get a googlecode for it.
Little tutorial on setup
Hello! This is a quick tutorial on how to use the updated version of Luddes, thumdecompiler.
Easy to use, with powerful results. That man is a genius. Anyway, it's helped me a lot and I hope it can help with malicious, or bad code or debug something that got compiled wrong
https://dl.dropbox.com/u/12510094/NEVERDELETE/IDATHUMBDECOMPILER.zip Plug in link
https://dl.dropbox.com/u/12510094/NEVERDELETE/thumb.zip Source code.
So....There are a ton of event check functions.
A lot are repeated, I believe the ones I labelled 2 are to check for the event to have occurred and ones without two are to check if the event is the current event or not
Anyway,
;
EVENT_AfterAuxEventSET: ; 0x801C0E8+2
int EVENT_AfterAuxEventSET() {
R1 = (EventCounter != 0x4B ? 0 : 1)
return R1
}
; End of function EVENT_AfterAuxEventSET
;
EVENT_EngagedSaXSET: ; 0x801C0E8:loc_801C120
int EVENT_EngagedSaXSET() {
R1 = (EventCounter != 0x4C ? 0 : 1)
return R1
}
; End of function EVENT_EngagedSaXSET
;
EVENT_IceBeamSET: ; 0x8010220+730
; sub_8010220+7C2 ...
int EVENT_IceBeamSET() {
R1 = (EventCounter <=u 0x6A ? 0 : 1)
return R1
}
; End of function EVENT_IceBeamSET
;
EVENT_FinalTripToHangerSET: ; 0x8054978+A
; sub_8054A3C+2A ...
int EVENT_FinalTripToHangerSET() {
R1 = (EventCounter <=u 0x69 ? 0 : 1)
return R1
}
; End of function EVENT_FinalTripToHangerSET
;
EVENT_FinalSAXFightSET: ; 0x801A914+2
int EVENT_FinalSAXFightSET() {
R1 = (EventCounter != 0x65 ? 0 : 1)
return R1
}
; End of function EVENT_FinalSAXFightSET
;
EVENT_BoxQuakeSET: ; CODE XREF: Enemy9F_AI+1B0
int EVENT_BoxQuakeSET() {
R1 = (EventCounter != 0x5A ? 0 : 1)
return R1
}
; End of function EVENT_BoxQuakeSET
;
EVENT_RestricttedLabBlockedSET: ; CODE XREF: Enemy9F_AI:loc_8030358
int EVENT_RestricttedLabBlockedSET() {
R1 = (EventCounter != 0x59 ? 0 : 1)
return R1
}
; End of function EVENT_RestricttedLabBlockedSET
;
EVENT_HasVariaSET: ; 0x80412F0+2C
int EVENT_HasVariaSET() {
R1 = (EventCounter <=u 0x33 ? 0 : 1)
return R1
}
; End of function EVENT_HasVariaSET
;
EVENT_IsPowerOutSET: ; 0x8056DF4+4A
int EVENT_IsPowerOutSET() {
R1 = EventCounter
R0 = 1
if (R1 == 0x46)
return R0
R0 = 0
if (R1 <=u 0x46)
return R0
return 2
}
; End of function EVENT_IsPowerOutSET
;
EVENT_HasWaveBeamSET: ; CODE XREF: Enemy9F_AI:loc_8030340
int EVENT_HasWaveBeamSET() {
R1 = (EventCounter != 0x5B ? 0 : 1)
return R1
}
; End of function EVENT_HasWaveBeamSET
;
EVENT_ReachedDeadEndRestrictedSET: ; CODE XREF: Enemy9F_AI:loc_803034C
; Enemy9F_AI+1DC ...
int EVENT_ReachedDeadEndRestrictedSET() {
R1 = (EventCounter != 0x5C ? 0 : 1)
return R1
}
; End of function EVENT_ReachedDeadEndRestrictedSET
;
EVENT_AfterBombsSET: ; CODE XREF: Enemy9F_AI+184
int EVENT_AfterBombsSET() {
R1 = (EventCounter != 0x17 ? 0 : 1)
return R1
}
; End of function EVENT_AfterBombsSET
;
sub_8060C78: ; CODE XREF: Enemy9F_AI:loc_8030334
int sub_8060C78() {
R1 = (EventCounter != 0x16 ? 0 : 1)
return R1
}
; End of function sub_8060C78
;
EVENT_EscSaxBeforVariaSET: ; 0x804378C+E0
int EVENT_EscSaxBeforVariaSET() {
R1 = (EventCounter != 0x31 ? 0 : 1)
return R1
}
; End of function EVENT_EscSaxBeforVariaSET
;
EVENT_SAXEntersPostPBSET: ; 0x80193C4:loc_8019428
; sub_8019520+4
int EVENT_SAXEntersPostPBSET() {
R1 = (EventCounter != 0x43 ? 0 : 1)
return R1
}
; End of function EVENT_SAXEntersPostPBSET
;
sub_8060CC0: ; 0x80193C4+3C
int sub_8060CC0() {
R1 = (EventCounter != 0x42 ? 0 : 1)
return R1
}
; End of function sub_8060CC0
;
EVENT_SAXEntersPreVariaSET: ; CODE XREF: PowerBombSaxInit+F
; BeginSAXRoutine+2
int EVENT_SAXEntersPreVariaSET() {
R1 = (EventCounter != 0x30 ? 0 : 1)
return R1
}
; End of function EVENT_SAXEntersPreVariaSET
;
EVENT_GoGetVariaSET: ; CODE XREF: PowerBombSaxInit+8
int EVENT_GoGetVariaSET() {
R1 = (EventCounter != 0x2F ? 0 : 1)
return R1
}
; End of function EVENT_GoGetVariaSET
;
EVENT_GotHighJumpSET: ; CODE XREF: SomeSaxRoutine+2
int EVENT_GotHighJumpSET() {
R1 = (EventCounter != 0x19 ? 0 : 1)
return R1
}
; End of function EVENT_GotHighJumpSET
;
EVENT_GotHighJump2SET: ; 0x80429B8+2
; Enemy89_AI:loc_8042B7A
int EVENT_GotHighJump2SET() {
R1 = (EventCounter <=u 0x19 ? 0 : 1)
return R1
}
; End of function EVENT_GotHighJump2SET
;
EVENT_TriggeredBOXSET: ; 0x8037E18+6E
; sub_803808C+242 ...
int EVENT_TriggeredBOXSET() {
R1 = (EventCounter <=u 0x27 ? 0 : 1)
return R1
}
; End of function EVENT_TriggeredBOXSET
;
EVENT_TriggeredBOX2SET: ; CODE XREF: Enemy20_AI:loc_803061A
; sub_8035C58+4
int EVENT_TriggeredBOX2SET() {
R1 = (EventCounter != 0x27 ? 0 : 1)
return R1
}
; End of function EVENT_TriggeredBOX2SET
;
EVENT_HaveSuperMissilesSET: ; CODE XREF: Enemy9F_AI+14C
; Enemy20_AI:loc_803059E
int EVENT_HaveSuperMissilesSET() {
R1 = (EventCounter != 0x26 ? 0 : 1)
return R1
}
; End of function EVENT_HaveSuperMissilesSET
;
EVENT_IsInSuperMissileRoomSET: ; CODE XREF: Enemy9F_AI:loc_8030328
int EVENT_IsInSuperMissileRoomSET() {
R1 = (EventCounter != 0x25 ? 0 : 1)
return R1
}
; End of function EVENT_IsInSuperMissileRoomSET
;
EVENT_EnteredPumpControlSET: ; 0x8030E14:loc_8030E96
int EVENT_EnteredPumpControlSET() {
R1 = (EventCounter <=u 0x1F ? 0 : 1)
return R1
}
; End of function EVENT_EnteredPumpControlSET
;
EVENT_OnToQuarantineBaySET: ; 0x801CA1C+A
int EVENT_OnToQuarantineBaySET() {
R1 = (EventCounter != 1 ? 0 : 1)
return R1
}
; End of function EVENT_OnToQuarantineBaySET
;
EVENT_GenericSet: ; 0x801F2C0+36
int EVENT_GenericSet() {
R2 = 0
R1 = EventCounter
if ((R1 - 0x3B & 0xFF) <=u 1 || (R1 - 0x46 & 0xFF) <=u 3 || R1 >u 0x66)
R2 = 1
return R2
}
; End of function EVENT_GenericSet
;
EVENT_Generic2Set: ; 0x802A11C+5C
int EVENT_Generic2Set() {
R2 = 0
R1 = EventCounter
if ((R1 - 0x46 & 0xFF) <=u 3 || R1 >u 0x66)
R2 = 1
return R2
}
; End of function EVENT_Generic2Set
;
EVENT_Generic3Set: ; 0x802BEC4+42
int EVENT_Generic3Set() {
R1 = ((EventCounter - 0x46 & 0xFF) >u 3 ? 0 : 1)
return R1
}
; End of function EVENT_Generic3Set
.align 4
.long EventCounter
;
EVENT_EnteredPumpControl2SET: ; 0x8039248:loc_80392AE
int EVENT_EnteredPumpControl2SET() {
R1 = (EventCounter != 0x1F ? 0 : 1)
return R1
}
; End of function EVENT_EnteredPumpControl2SET
;
EVENT_WideBeamGETorMeltdownSET: ; 0x8039248:loc_80392B4
; sub_8039680+A ...
int EVENT_WideBeamGETorMeltdownSET() {
R1 = 0
R0 = EventCounter
if (R0 == 0x3B) {
R1 = 1
return R1
}
if (R0 == 0x3C)
R1 = 2
return R1
}
; End of function EVENT_WideBeamGETorMeltdownSET
;
EVENT_TharBeWildLifeSET: ; 0x8039248:loc_80392E6
int EVENT_TharBeWildLifeSET() {
R1 = (EventCounter != 0x3E ? 0 : 1)
return R1
}
; End of function EVENT_TharBeWildLifeSET
;
EVENT_TharBeWildLife2SET: ; 0x8030868+BE
; sub_80309A0:loc_80309B2 ...
int EVENT_TharBeWildLife2SET() {
R1 = (EventCounter <=u 0x3E ? 0 : 1)
return R1
}
; End of function EVENT_TharBeWildLife2SET
;
EVENT_HasSpaceJump: ; 0x8039248:loc_80392DC
int EVENT_HasSpaceJump() {
R1 = (EventCounter != 0x49 ? 0 : 1)
return R1
}
; End of function EVENT_HasSpaceJump
;
EVENT_SAXSaviorEscapesSET: ; 0x80399B0+64
int EVENT_SAXSaviorEscapesSET() {
R1 = (EventCounter != 0x66 ? 0 : 1)
return R1
}
; End of function EVENT_SAXSaviorEscapesSET
;
EVENT_SAXSaviorEscapes2SET: ; 0x80399B0:loc_8039A40
int EVENT_SAXSaviorEscapes2SET() {
R1 = (EventCounter <=u 0x66 ? 0 : 1)
return R1
}
;EVENT_SAXSaviorEscapes2SET
;
GetWhichTimer: ; 0x802A310+2
; sub_804F614+2 ...
int GetWhichTimer() {
R2 = 0
R0 = EventCounter - 0x3B
if (R0 >u 0x31)
return R2
if (R0 == 0 || R0 == 1) {
R2 = 1
return R2
}
if (R0 == 2 || R0 == 3 || R0 == 4 || R0 == 5 || R0 == 6 || R0 == 7 || R0 == 8 || R0 == 9 || R0 == 0xA || R0 == 0xB || R0 == 0xC || R0 == 0xD || R0 == 0xE || R0 == 0xF || R0 == 0x10 || R0 == 0x11 || R0 == 0x12 || R0 == 0x13 || R0 == 0x14 || R0 == 0x15 || R0 == 0x16 || R0 == 0x17 || R0 == 0x18 || R0 == 0x19 || R0 == 0x1A || R0 == 0x1B || R0 == 0x1C || R0 == 0x1D || R0 == 0x1E || R0
return R2
if (R0 == 0x22) {
R2 = 2
return R2
}
if (R0 == 0x23 || R0 == 0x24 || R0 == 0x25 || R0 == 0x26 || R0 == 0x27 || R0 == 0x28 || R0 == 0x29 || R0 == 0x2A || R0 == 0x2B)
return R2
if (R0 != 0x2C && R0 != 0x2D && R0 != 0x2E && R0 != 0x2F && R0 == 0x30) {
}
R2 = 3
return R2
}
;GetWhichTimer
;
EVENT_CheckMajorEventsSET: ; 0x80746CC+64 p
int EVENT_CheckMajorEventsSET() {
R1 = 0
R0 = EventCounter
if (R0 == 0x3D || R0 == 0x5E || R0 == 0x6D)
R1 = 1
return R1
}
;EVENT_CheckMajorEventsSET
A lot are repeated, I believe the ones I labelled 2 are to check for the event to have occurred and ones without two are to check if the event is the current event or not
Anyway,
;
EVENT_AfterAuxEventSET: ; 0x801C0E8+2
int EVENT_AfterAuxEventSET() {
R1 = (EventCounter != 0x4B ? 0 : 1)
return R1
}
; End of function EVENT_AfterAuxEventSET
;
EVENT_EngagedSaXSET: ; 0x801C0E8:loc_801C120
int EVENT_EngagedSaXSET() {
R1 = (EventCounter != 0x4C ? 0 : 1)
return R1
}
; End of function EVENT_EngagedSaXSET
;
EVENT_IceBeamSET: ; 0x8010220+730
; sub_8010220+7C2 ...
int EVENT_IceBeamSET() {
R1 = (EventCounter <=u 0x6A ? 0 : 1)
return R1
}
; End of function EVENT_IceBeamSET
;
EVENT_FinalTripToHangerSET: ; 0x8054978+A
; sub_8054A3C+2A ...
int EVENT_FinalTripToHangerSET() {
R1 = (EventCounter <=u 0x69 ? 0 : 1)
return R1
}
; End of function EVENT_FinalTripToHangerSET
;
EVENT_FinalSAXFightSET: ; 0x801A914+2
int EVENT_FinalSAXFightSET() {
R1 = (EventCounter != 0x65 ? 0 : 1)
return R1
}
; End of function EVENT_FinalSAXFightSET
;
EVENT_BoxQuakeSET: ; CODE XREF: Enemy9F_AI+1B0
int EVENT_BoxQuakeSET() {
R1 = (EventCounter != 0x5A ? 0 : 1)
return R1
}
; End of function EVENT_BoxQuakeSET
;
EVENT_RestricttedLabBlockedSET: ; CODE XREF: Enemy9F_AI:loc_8030358
int EVENT_RestricttedLabBlockedSET() {
R1 = (EventCounter != 0x59 ? 0 : 1)
return R1
}
; End of function EVENT_RestricttedLabBlockedSET
;
EVENT_HasVariaSET: ; 0x80412F0+2C
int EVENT_HasVariaSET() {
R1 = (EventCounter <=u 0x33 ? 0 : 1)
return R1
}
; End of function EVENT_HasVariaSET
;
EVENT_IsPowerOutSET: ; 0x8056DF4+4A
int EVENT_IsPowerOutSET() {
R1 = EventCounter
R0 = 1
if (R1 == 0x46)
return R0
R0 = 0
if (R1 <=u 0x46)
return R0
return 2
}
; End of function EVENT_IsPowerOutSET
;
EVENT_HasWaveBeamSET: ; CODE XREF: Enemy9F_AI:loc_8030340
int EVENT_HasWaveBeamSET() {
R1 = (EventCounter != 0x5B ? 0 : 1)
return R1
}
; End of function EVENT_HasWaveBeamSET
;
EVENT_ReachedDeadEndRestrictedSET: ; CODE XREF: Enemy9F_AI:loc_803034C
; Enemy9F_AI+1DC ...
int EVENT_ReachedDeadEndRestrictedSET() {
R1 = (EventCounter != 0x5C ? 0 : 1)
return R1
}
; End of function EVENT_ReachedDeadEndRestrictedSET
;
EVENT_AfterBombsSET: ; CODE XREF: Enemy9F_AI+184
int EVENT_AfterBombsSET() {
R1 = (EventCounter != 0x17 ? 0 : 1)
return R1
}
; End of function EVENT_AfterBombsSET
;
sub_8060C78: ; CODE XREF: Enemy9F_AI:loc_8030334
int sub_8060C78() {
R1 = (EventCounter != 0x16 ? 0 : 1)
return R1
}
; End of function sub_8060C78
;
EVENT_EscSaxBeforVariaSET: ; 0x804378C+E0
int EVENT_EscSaxBeforVariaSET() {
R1 = (EventCounter != 0x31 ? 0 : 1)
return R1
}
; End of function EVENT_EscSaxBeforVariaSET
;
EVENT_SAXEntersPostPBSET: ; 0x80193C4:loc_8019428
; sub_8019520+4
int EVENT_SAXEntersPostPBSET() {
R1 = (EventCounter != 0x43 ? 0 : 1)
return R1
}
; End of function EVENT_SAXEntersPostPBSET
;
sub_8060CC0: ; 0x80193C4+3C
int sub_8060CC0() {
R1 = (EventCounter != 0x42 ? 0 : 1)
return R1
}
; End of function sub_8060CC0
;
EVENT_SAXEntersPreVariaSET: ; CODE XREF: PowerBombSaxInit+F
; BeginSAXRoutine+2
int EVENT_SAXEntersPreVariaSET() {
R1 = (EventCounter != 0x30 ? 0 : 1)
return R1
}
; End of function EVENT_SAXEntersPreVariaSET
;
EVENT_GoGetVariaSET: ; CODE XREF: PowerBombSaxInit+8
int EVENT_GoGetVariaSET() {
R1 = (EventCounter != 0x2F ? 0 : 1)
return R1
}
; End of function EVENT_GoGetVariaSET
;
EVENT_GotHighJumpSET: ; CODE XREF: SomeSaxRoutine+2
int EVENT_GotHighJumpSET() {
R1 = (EventCounter != 0x19 ? 0 : 1)
return R1
}
; End of function EVENT_GotHighJumpSET
;
EVENT_GotHighJump2SET: ; 0x80429B8+2
; Enemy89_AI:loc_8042B7A
int EVENT_GotHighJump2SET() {
R1 = (EventCounter <=u 0x19 ? 0 : 1)
return R1
}
; End of function EVENT_GotHighJump2SET
;
EVENT_TriggeredBOXSET: ; 0x8037E18+6E
; sub_803808C+242 ...
int EVENT_TriggeredBOXSET() {
R1 = (EventCounter <=u 0x27 ? 0 : 1)
return R1
}
; End of function EVENT_TriggeredBOXSET
;
EVENT_TriggeredBOX2SET: ; CODE XREF: Enemy20_AI:loc_803061A
; sub_8035C58+4
int EVENT_TriggeredBOX2SET() {
R1 = (EventCounter != 0x27 ? 0 : 1)
return R1
}
; End of function EVENT_TriggeredBOX2SET
;
EVENT_HaveSuperMissilesSET: ; CODE XREF: Enemy9F_AI+14C
; Enemy20_AI:loc_803059E
int EVENT_HaveSuperMissilesSET() {
R1 = (EventCounter != 0x26 ? 0 : 1)
return R1
}
; End of function EVENT_HaveSuperMissilesSET
;
EVENT_IsInSuperMissileRoomSET: ; CODE XREF: Enemy9F_AI:loc_8030328
int EVENT_IsInSuperMissileRoomSET() {
R1 = (EventCounter != 0x25 ? 0 : 1)
return R1
}
; End of function EVENT_IsInSuperMissileRoomSET
;
EVENT_EnteredPumpControlSET: ; 0x8030E14:loc_8030E96
int EVENT_EnteredPumpControlSET() {
R1 = (EventCounter <=u 0x1F ? 0 : 1)
return R1
}
; End of function EVENT_EnteredPumpControlSET
;
EVENT_OnToQuarantineBaySET: ; 0x801CA1C+A
int EVENT_OnToQuarantineBaySET() {
R1 = (EventCounter != 1 ? 0 : 1)
return R1
}
; End of function EVENT_OnToQuarantineBaySET
;
EVENT_GenericSet: ; 0x801F2C0+36
int EVENT_GenericSet() {
R2 = 0
R1 = EventCounter
if ((R1 - 0x3B & 0xFF) <=u 1 || (R1 - 0x46 & 0xFF) <=u 3 || R1 >u 0x66)
R2 = 1
return R2
}
; End of function EVENT_GenericSet
;
EVENT_Generic2Set: ; 0x802A11C+5C
int EVENT_Generic2Set() {
R2 = 0
R1 = EventCounter
if ((R1 - 0x46 & 0xFF) <=u 3 || R1 >u 0x66)
R2 = 1
return R2
}
; End of function EVENT_Generic2Set
;
EVENT_Generic3Set: ; 0x802BEC4+42
int EVENT_Generic3Set() {
R1 = ((EventCounter - 0x46 & 0xFF) >u 3 ? 0 : 1)
return R1
}
; End of function EVENT_Generic3Set
.align 4
.long EventCounter
;
EVENT_EnteredPumpControl2SET: ; 0x8039248:loc_80392AE
int EVENT_EnteredPumpControl2SET() {
R1 = (EventCounter != 0x1F ? 0 : 1)
return R1
}
; End of function EVENT_EnteredPumpControl2SET
;
EVENT_WideBeamGETorMeltdownSET: ; 0x8039248:loc_80392B4
; sub_8039680+A ...
int EVENT_WideBeamGETorMeltdownSET() {
R1 = 0
R0 = EventCounter
if (R0 == 0x3B) {
R1 = 1
return R1
}
if (R0 == 0x3C)
R1 = 2
return R1
}
; End of function EVENT_WideBeamGETorMeltdownSET
;
EVENT_TharBeWildLifeSET: ; 0x8039248:loc_80392E6
int EVENT_TharBeWildLifeSET() {
R1 = (EventCounter != 0x3E ? 0 : 1)
return R1
}
; End of function EVENT_TharBeWildLifeSET
;
EVENT_TharBeWildLife2SET: ; 0x8030868+BE
; sub_80309A0:loc_80309B2 ...
int EVENT_TharBeWildLife2SET() {
R1 = (EventCounter <=u 0x3E ? 0 : 1)
return R1
}
; End of function EVENT_TharBeWildLife2SET
;
EVENT_HasSpaceJump: ; 0x8039248:loc_80392DC
int EVENT_HasSpaceJump() {
R1 = (EventCounter != 0x49 ? 0 : 1)
return R1
}
; End of function EVENT_HasSpaceJump
;
EVENT_SAXSaviorEscapesSET: ; 0x80399B0+64
int EVENT_SAXSaviorEscapesSET() {
R1 = (EventCounter != 0x66 ? 0 : 1)
return R1
}
; End of function EVENT_SAXSaviorEscapesSET
;
EVENT_SAXSaviorEscapes2SET: ; 0x80399B0:loc_8039A40
int EVENT_SAXSaviorEscapes2SET() {
R1 = (EventCounter <=u 0x66 ? 0 : 1)
return R1
}
;EVENT_SAXSaviorEscapes2SET
;
GetWhichTimer: ; 0x802A310+2
; sub_804F614+2 ...
int GetWhichTimer() {
R2 = 0
R0 = EventCounter - 0x3B
if (R0 >u 0x31)
return R2
if (R0 == 0 || R0 == 1) {
R2 = 1
return R2
}
if (R0 == 2 || R0 == 3 || R0 == 4 || R0 == 5 || R0 == 6 || R0 == 7 || R0 == 8 || R0 == 9 || R0 == 0xA || R0 == 0xB || R0 == 0xC || R0 == 0xD || R0 == 0xE || R0 == 0xF || R0 == 0x10 || R0 == 0x11 || R0 == 0x12 || R0 == 0x13 || R0 == 0x14 || R0 == 0x15 || R0 == 0x16 || R0 == 0x17 || R0 == 0x18 || R0 == 0x19 || R0 == 0x1A || R0 == 0x1B || R0 == 0x1C || R0 == 0x1D || R0 == 0x1E || R0
return R2
if (R0 == 0x22) {
R2 = 2
return R2
}
if (R0 == 0x23 || R0 == 0x24 || R0 == 0x25 || R0 == 0x26 || R0 == 0x27 || R0 == 0x28 || R0 == 0x29 || R0 == 0x2A || R0 == 0x2B)
return R2
if (R0 != 0x2C && R0 != 0x2D && R0 != 0x2E && R0 != 0x2F && R0 == 0x30) {
}
R2 = 3
return R2
}
;GetWhichTimer
;
EVENT_CheckMajorEventsSET: ; 0x80746CC+64 p
int EVENT_CheckMajorEventsSET() {
R1 = 0
R0 = EventCounter
if (R0 == 0x3D || R0 == 0x5E || R0 == 0x6D)
R1 = 1
return R1
}
;EVENT_CheckMajorEventsSET
ASM post coming soon!
Sunday or Monday, the next tutorial will be up!
We will again be hacking Metroid Fusion.
Our goal this time, will be to completely fill up our energy whenever we pass through a door.
I will be issuing homework I hope some will try it!
We will be learning how to track down our target addresses.
Learn how to Hi-Jack addresses
And how to return :D
I'm not the best, but it works well and that's how I'm teaching!
We will again be hacking Metroid Fusion.
Our goal this time, will be to completely fill up our energy whenever we pass through a door.
I will be issuing homework I hope some will try it!
We will be learning how to track down our target addresses.
Learn how to Hi-Jack addresses
And how to return :D
I'm not the best, but it works well and that's how I'm teaching!
Tuesday, January 29, 2013
Romhacking misconceptions
Today I'd like to talk about a few common misconceptions when hacking.
"I can't hex"
Look bro, I don't care who you are "hex" is not an action. It's a type of counting system
01-0F, and so on.
Just forget the term hex if it bothers you that much. Just refer to it as data however.
If you see 0x
Such as 0x0BADC0DE the 0x indicates we're using the hexadecimal system.
Now when you pull up a ROM in a hex editor, you'll see this
This image shows many things, but you're probably confused.
This is called a GBA header. It's of course stored in a binary data format. But since we know it's a GBA game header, we can just find the header structure on google and apply the info.
Here's the structure
0x000h 4 ROM Entry Point (32bit ARM branch opcode, eg. "B rom_start") 0x004h 156 Nintendo Logo (compressed bitmap, required!)
0x0A0h 12 Game Title (uppercase ascii, max 12 characters)
0x0ACh 4 Game Code (uppercase ascii, 4 characters)
0x0B0h 2 Maker Code (uppercase ascii, 2 characters)
0x0B2h 1 Fixed value (must be 96h, required!)
0x0B3h 1 Main unit code (00h for current GBA models)
0x0B4h 1 Device type (usually 00h)
0x0B5h 7 Reserved Area (should be zero filled)
0x0BCh 1 Software version (usually 00h)
0x0BDh 1 Complement check (header checksum, required!)
0x0BEh 2 Reserved Area (should be zero filled)
So according to this, the first 4 bytes are an assembly instruction on where to start the game.
Then is a compressed image(Yes, that's stored in our hexadecimal data format)
Then so on.
Data is nothing to be scared of. The editors you use, the game itself relies on
the data.
Let's move on to pointers.
They're scary for a lot of newbies. I didn't quite get them when I first started,but now I rely on them.
It's super simple
For GBA
it's just address+0x8000000 and it's stored backwards in the rom
So the pointer 0x08123456 would be stored in rom at 56 34 12 08
Codes uses the pointer to get the address of the data.
Just add 0x8000000 for ROM pointers. Simple no?
Assembly is just a way of seeing the data as somewhat readable
nop instead of 0x46c0.
It's not hard and just needs to be learned.
If you have any questions, leave a comment. I'll get back to you.
"I can't hex"
Look bro, I don't care who you are "hex" is not an action. It's a type of counting system
01-0F, and so on.
Just forget the term hex if it bothers you that much. Just refer to it as data however.
If you see 0x
Such as 0x0BADC0DE the 0x indicates we're using the hexadecimal system.
Now when you pull up a ROM in a hex editor, you'll see this
This image shows many things, but you're probably confused.
This is called a GBA header. It's of course stored in a binary data format. But since we know it's a GBA game header, we can just find the header structure on google and apply the info.
Here's the structure
0x000h 4 ROM Entry Point (32bit ARM branch opcode, eg. "B rom_start") 0x004h 156 Nintendo Logo (compressed bitmap, required!)
0x0A0h 12 Game Title (uppercase ascii, max 12 characters)
0x0ACh 4 Game Code (uppercase ascii, 4 characters)
0x0B0h 2 Maker Code (uppercase ascii, 2 characters)
0x0B2h 1 Fixed value (must be 96h, required!)
0x0B3h 1 Main unit code (00h for current GBA models)
0x0B4h 1 Device type (usually 00h)
0x0B5h 7 Reserved Area (should be zero filled)
0x0BCh 1 Software version (usually 00h)
0x0BDh 1 Complement check (header checksum, required!)
0x0BEh 2 Reserved Area (should be zero filled)
So according to this, the first 4 bytes are an assembly instruction on where to start the game.
Then is a compressed image(Yes, that's stored in our hexadecimal data format)
Then so on.
Data is nothing to be scared of. The editors you use, the game itself relies on
the data.
Let's move on to pointers.
They're scary for a lot of newbies. I didn't quite get them when I first started,but now I rely on them.
It's super simple
For GBA
it's just address+0x8000000 and it's stored backwards in the rom
So the pointer 0x08123456 would be stored in rom at 56 34 12 08
Codes uses the pointer to get the address of the data.
Just add 0x8000000 for ROM pointers. Simple no?
Assembly is just a way of seeing the data as somewhat readable
nop instead of 0x46c0.
It's not hard and just needs to be learned.
If you have any questions, leave a comment. I'll get back to you.
Sunday, January 27, 2013
Thumb Decompiler update
Hey guys!
So the progress of the Thumb Decompiler plugin is going great. I'll be releasing the update for it soon. Source included of course as per the original thumb decompiler.
Here's a screenie!
I need to get the decompiled code to redirect to a new tab, get stack variables going. And some other stuff. But hopefully soon!
So the progress of the Thumb Decompiler plugin is going great. I'll be releasing the update for it soon. Source included of course as per the original thumb decompiler.
Here's a screenie!
I need to get the decompiled code to redirect to a new tab, get stack variables going. And some other stuff. But hopefully soon!
Friday, January 25, 2013
Your first GBA ASM hack!
Greetings! Today I will teach you how to find what you need to find using a debugger, then how to change it. Then what else you can do!
You will need no$gba debugger, or a sufficient GBA emulator with a good debugger. Grab a Metroid Fusion ROM(Rip your own preferably) and get a hex editor. I heard HxD is good.
We are going to find out how to get rid of Samus freezing her butt off in NOC with no Varia suit.
So, grab your emulator, load Fusion and head to ARC.
We'll need to know the current health samus has, load up Datacrystal.org and go to Fusion then RAM Map. This gives us the address of 3001310. Head to the room before it gets icy.
In no$gba(Or whatever debugger you have) set a breakpoint for when Samus's health gets a write(That means when something changes it) hit ctrl+b on your keyboard!
Now enter [3001310]!!(Or the equivalent in your debugger)
Continue playing until the emulator stops.
Woo! It hit.
You'll see something like
What do these lines mean?
080063CE LDRH R0, [R2]
080063D0 SUBS R0, #1
080063D2 STRH R0, [R2]
080063D4 LDRH R0, [R2] <---You'll break here
You'll basically encounter 3 variable types when hacking
Byte, Short, Long
1 Byte for a byte, 2 bytes for a short and 4 bytes for a long
Byte can hold 0-255
Short can hold 0-65535(0xFFFF)
And Long can hold 0-4294967295(0xFFFFFFFF)
Wow that's a lot!
So what does the following mean?!
080063CE LDRH R0, [R2]
080063D0 SUBS R0, #1
080063D2 STRH R0, [R2]
080063D4 LDRH R0, [R2]
LDRH means LoadRegisterHalfword
or Load a short
What it does is it reads 2 bytes from whatever address is in the Register R2 and puts them into 0
STRH is the same, except it stores.
And of course SUBS R0, #1 is subtract 1 from R0
In this tutorial we'll do 3 different things.
Delete the breakpoint, and write down the offset 080063D0 which has the SUBs instruction.
Make a save state and let's do some hacking
In your debugger, go to
080063D0
type nop in, and it will appear in the debugger.
Now go to the frozen zone and bamf! No more damage.
Reload the rom and open your savestate, go to that address again. Type in ADD R0, 3
Then watch Samus gain health quickly.
Now, let's change it back to nop look at the two bytes to the right of the subs r0, #1 instruction.
3801
Now if you go to the data viewer(At least in no$gba) and go to that address it'll look like
01 38
AND THAT IS A'OKAY.
Now change the instruction to nop then those two bytes next to nop will be 46C0, and again if you look in the dataviewer it will be c0 46!
Now, that's cool but these results aren't saved to our ROM
Open up the ROM in your hex editor!
Let's have a quick lesson about GBA Addressing.
It's super simple.
The address 0x080063D0 we're playing with, in your hexeditor will be at 0x63D0
Just subtract 0x8000000 to convert(Or add in case of pointers)
So now go to 0x63D0 type c0 46 at the offset, save then test! No more damage in ARC! :)
Video included.
You will need no$gba debugger, or a sufficient GBA emulator with a good debugger. Grab a Metroid Fusion ROM(Rip your own preferably) and get a hex editor. I heard HxD is good.
We are going to find out how to get rid of Samus freezing her butt off in NOC with no Varia suit.
So, grab your emulator, load Fusion and head to ARC.
We'll need to know the current health samus has, load up Datacrystal.org and go to Fusion then RAM Map. This gives us the address of 3001310. Head to the room before it gets icy.
In no$gba(Or whatever debugger you have) set a breakpoint for when Samus's health gets a write(That means when something changes it) hit ctrl+b on your keyboard!
Now enter [3001310]!!(Or the equivalent in your debugger)
Continue playing until the emulator stops.
Woo! It hit.
You'll see something like
What do these lines mean?
080063CE LDRH R0, [R2]
080063D0 SUBS R0, #1
080063D2 STRH R0, [R2]
080063D4 LDRH R0, [R2] <---You'll break here
You'll basically encounter 3 variable types when hacking
Byte, Short, Long
1 Byte for a byte, 2 bytes for a short and 4 bytes for a long
Byte can hold 0-255
Short can hold 0-65535(0xFFFF)
And Long can hold 0-4294967295(0xFFFFFFFF)
Wow that's a lot!
So what does the following mean?!
080063CE LDRH R0, [R2]
080063D0 SUBS R0, #1
080063D2 STRH R0, [R2]
080063D4 LDRH R0, [R2]
LDRH means LoadRegisterHalfword
or Load a short
What it does is it reads 2 bytes from whatever address is in the Register R2 and puts them into 0
STRH is the same, except it stores.
And of course SUBS R0, #1 is subtract 1 from R0
In this tutorial we'll do 3 different things.
Delete the breakpoint, and write down the offset 080063D0 which has the SUBs instruction.
Make a save state and let's do some hacking
In your debugger, go to
080063D0
type nop in, and it will appear in the debugger.
Now go to the frozen zone and bamf! No more damage.
Reload the rom and open your savestate, go to that address again. Type in ADD R0, 3
Then watch Samus gain health quickly.
Now, let's change it back to nop look at the two bytes to the right of the subs r0, #1 instruction.
3801
Now if you go to the data viewer(At least in no$gba) and go to that address it'll look like
01 38
AND THAT IS A'OKAY.
Now change the instruction to nop then those two bytes next to nop will be 46C0, and again if you look in the dataviewer it will be c0 46!
Now, that's cool but these results aren't saved to our ROM
Open up the ROM in your hex editor!
Let's have a quick lesson about GBA Addressing.
It's super simple.
The address 0x080063D0 we're playing with, in your hexeditor will be at 0x63D0
Just subtract 0x8000000 to convert(Or add in case of pointers)
So now go to 0x63D0 type c0 46 at the offset, save then test! No more damage in ARC! :)
Video included.
IDA Pro is best
Several weeks ago I found a plugin called Thumb decompiler, it does as it says. However it's around 6 or 7 years old and hasn't been updated. I grabbed the source and began modifying it, so far I only managed to fix one bug. But the plugins code is genius, it's made by a person named Ludde. Genius, simply genius. I'm adding to the plugin currently working on getting the decompiled code to it's own subview. I just figured out how to create subviews so it should be a piece of cake from there here's a picture!
I will release the plugin on this blog once I have substantial work put into it such as getting stack vars going and such.
I will release the plugin on this blog once I have substantial work put into it such as getting stack vars going and such.
Wednesday, January 23, 2013
Thursday, January 17, 2013
Metroid Fusions debug menu and Zero Missions forced lack of
Greetings!
I have a vast love for the Metroid series. It was the one I played with my parents when I was a toddler and such. I sadly only own Zero Mission and Fusion.
A friend of mine had told of me debug event text in Metroid Fusion, I have started a hack of Fusion to expand on it and I wanted this info for my ROM map. So he gives it to me, then I find what looks like a DrawText function near it and knew I was on to something. Faster forward 15 hours later, we had a full working Metroid Fusion debug menu. That NO ONE knew about outside of Nintendo for 11 years!
It's extremely powerful. I love Nintendo so hard.
So here is a video of it!
And so I also delved in the ZM rom for a bit.
While I didn't find anything new, I did look at Trunaur86s old menu hack for the on/off button.
When looking at the code, I discovered they intentionally removed access to it.
There's a register 'R6' which hold basically the onffswitch val. And the sets it to 0 and does checks to make sure it's 0, where as if it's non-zero you get the onoffswitch!
I have a vast love for the Metroid series. It was the one I played with my parents when I was a toddler and such. I sadly only own Zero Mission and Fusion.
A friend of mine had told of me debug event text in Metroid Fusion, I have started a hack of Fusion to expand on it and I wanted this info for my ROM map. So he gives it to me, then I find what looks like a DrawText function near it and knew I was on to something. Faster forward 15 hours later, we had a full working Metroid Fusion debug menu. That NO ONE knew about outside of Nintendo for 11 years!
It's extremely powerful. I love Nintendo so hard.
So here is a video of it!
And so I also delved in the ZM rom for a bit.
While I didn't find anything new, I did look at Trunaur86s old menu hack for the on/off button.
When looking at the code, I discovered they intentionally removed access to it.
There's a register 'R6' which hold basically the onffswitch val. And the sets it to 0 and does checks to make sure it's 0, where as if it's non-zero you get the onoffswitch!
Sunday, January 6, 2013
New projects
Greetings,
I'm currently undertaking many projects and so I'll be posting here with how I'm doing them. Or tutorials to get others started.
So, that's it for this one. I'll probably begin another one today
I'm currently undertaking many projects and so I'll be posting here with how I'm doing them. Or tutorials to get others started.
So, that's it for this one. I'll probably begin another one today
Subscribe to:
Posts (Atom)