Final Fantasy® VII Searches

Share Your Script Searches With the World

Moderators: g3nuin3, SpeedWing, WhiteHat, mezzo

Final Fantasy® VII Searches

Postby L. Spiro » Thu Aug 03, 2006 10:45 pm

Game: Final Fantasy® VII
Purpose: Find Accesory and Armor data blocks and to find your player information during a battle.

Use FF7AccSearchSetup() to find accessories.
Use FF7ArmorSearchSetup() to find armors.
Use FF7BPlayerSearchSetup() to find your player battle data (you must fight a battle to find this).
Use FF7SearchSetup() to find all of the above.


The range to search should be from 0x00400000 to 0x00FFFFFF.
Searching the full user-mode range may take about one minute for the FF7Search() search.



Code: Select all
// Search for accessory data.
// I happen to know the structure format
//  for accessory data already, so just assume
//  I am right.
INT FF7AccSearch( LPVOID lpvAddress, LPVOID lpvBuffer, INT iSize ) {
    struct FF7_Acc {
        BYTE        bIncType[2];    // Stat increase type.
                                    //  00 = Str, 01 = Vit, 02 = Mag,
                                    //  03 = Spir, 04 = Dex, 05 = Luck
                                    //  FF = None.  Two bytes.
        BYTE        bIncBy[2];      // Amount by which the stats
                                    //  above increase.
        BYTE        bElemStr;       // Elemental strength.  0, 1, 0r FF.
        BYTE        bSpecEff;       // Special effects.  0-6 or FF.
        WORD        wElementType;   // Element.
        DWORD       dwStatus;       // Status protection.
        WORD        wEquipMask;     // Always FF 01.
        BYTE        bRestMask;      // F6 to FF (but always FE for accessories).
        BYTE        bPad;           // Pad, always FF.
    }   * pff7aAcc = lpvBuffer;     // Cast the buffer to this type.

    // There are several fast checks we should do first.
    // Firstly, we should check that the buffer is large enough for
    //  this structure.
    if ( iSize < sizeof( FF7_Acc ) ) { return 0; }

    // The last byte is always FF.  Easy to check.
    if ( pff7aAcc->bPad != 0xFF ) { return 0; }

    // The restriction mask is always FE for accessories.
    if ( pff7aAcc->bRestMask != 0xFE ) { return 0; }

    // The equipmask is always FF 01 (0x01FF).
    if ( pff7aAcc->wEquipMask != 0x01FF ) { return 0; }

    // These were the easy things to check.
    // The next items have valid ranges.

    // The Elemental Strength is 0, 1, or FF.
    BYTE bStr = pff7aAcc->bElemStr;
    if ( bStr > 0x01 && bStr != 0xFF ) { return 0; }

    // By now we have eliminated all fakers.
    //  We can test by simply performing a search.


    // Return the size of the structure.
    // In a fixed-size search this won’t matter, but in a variable--
    //  sized search this will cause the correct buffer size to be used.
    return sizeof( FF7_Acc );
}

VOID FF7AccSearchSetup( INT * piDataSize, INT * piAlign, CHAR ** ppcCallback, CHAR ** ppcDecoder ) {
    (*piDataSize) = sizeof( FF7_Acc );
    (*piAlign) = 4;
    (*ppcCallback) = "FF7AccSearch";
}


// Search for armor data.
INT FF7ArmorSearch( LPVOID lpvAddress, LPVOID lpvBuffer, INT iSize ) {
    struct FF7_Armor {
        BYTE        bUnknown;       // Some byte at the start which is only 0 or FF.
        BYTE        bDamageType;    // Damage type. FF = Normal. 0 = Absorb. 1 = None. 2 = Half.
        BYTE        bDef;           // Defense.
        BYTE        bMagicDef;      // Magic defense.
        BYTE        bDefPerc;       // Defense %.
        BYTE        bMagicDefPerc;  // Magic Defense %.
        WORD        wFill;          // Always FFFF.
        BYTE        bFill;          // Always 0 or FF.
        BYTE        bSlots[8];      // Slot links.
        BYTE        bGrowth;        // Growth rate. 0, 1, or 2.
        WORD        wEquipMask;     // Who can equip it?
        BYTE        bElemType[3];   // Element type.
        BYTE        bPad;           // Always FF.
        BYTE        bIncType[2];    // Stat increase type.
        WORD        wPad2;          // Always FFFF.
        BYTE        bIncAmount[2];  // Amount by which to increase stats in bIncType.
        WORD        wPad3;          // Always FFFF.
        BYTE        bRestMask;      // F6 to FF (but always FE for armors).
        BYTE        bPad4;          // Always FF.
        WORD        wPad5;          // Always FFFF.
    }   * pff7aAcc = lpvBuffer;     // Cast the buffer to this type.

    // Start with the fastest checks.
    if ( iSize < sizeof( FF7_Armor ) ) { return 0; }

    // The pad at the end is a good check to make.
    if ( pff7aAcc->wPad5 != 0xFFFF ) { return 0; }
    if ( pff7aAcc->bPad4 != 0xFF ) { return 0; }

    // The restriction mask is always FE.
    if ( pff7aAcc->bRestMask != 0xFE ) { return 0; }

    // wPad3 is always FFFF.
    if ( pff7aAcc->wPad3 != 0xFFFF ) { return 0; }

    // The rest of the pads.
    if ( pff7aAcc->wPad2 != 0xFFFF ) { return 0; }
    if ( pff7aAcc->bPad != 0xFF ) { return 0; }
    if ( pff7aAcc->wFill != 0xFFFF ) { return 0; }

    // Now there are a few members that can only have a few valid values.
    // Check those.
    if ( pff7aAcc->bUnknown != 0xFF && pff7aAcc->bUnknown != 0x00 ) { return 0; }
    if ( pff7aAcc->bFill != 0xFF && pff7aAcc->bFill != 0x00 ) { return 0; }

    // Lastly, all stats can not be FF.
    if ( *(DWORD *)&pff7aAcc->bDef == 0xFFFFFFFF ) { return 0; }

    // Getting here means the chances are pretty good that this is a valid item.
    // Return the size of the item to make this search compatible with both variable
    //  and fixed searches.
    return sizeof( FF7_Armor );
}

VOID FF7ArmorSearchSetup( INT * piDataSize, INT * piAlign, CHAR ** ppcCallback, CHAR ** ppcDecoder ) {
    (*piDataSize) = sizeof( FF7_Armor );
    (*piAlign) = 4;
    (*ppcCallback) = "FF7ArmorSearch";
}


// Search for player data.
INT FF7BPlayerSearch( LPVOID lpvAddress, LPVOID lpvBuffer, INT iSize ) {
    struct FF7_BPlayer {
        DWORD       dwStatus;       // Status inflictions.
        BYTE        bOrder;         // Fron/back/against enemy/defending.
        BYTE        bPad1;          // Always 0.
        WORD        wPad2;          // Always 0.
        BYTE        bCharID;        // Character ID.
        BYTE        bLevel;         // From 6 to 99.
        WORD        wPad3;          // Always 0.
        BYTE        bUnknown1;      // Something.
        BYTE        bPhysAtt;       // Physical attack.
        BYTE        MagAttack;      // Magic attack.
        BYTE        bPad4[5];       // 5 pad bytes.
        BYTE        bDex;           // Dexterity.
        BYTE        bLuck;          // Luck.
        DWORD       dwPad5;         // Always 0.
        DWORD       dwPad6;         // Always 0.
        WORD        wPad7;          // Always 0.
        WORD        wPhysDef;       // Physical defense.
        WORD        wMagicDefense;  // Magic Defense.
        DWORD       dwPad8;         // Always 0.
        WORD        wCurMP;         // Current MP.
        WORD        wMaxMP;         // Max MP.
        DWORD       dwCurHP;        // Current HP.
        DWORD       dwMaxHP;        // Max HP.
        BYTE        bPad9[16];      // 0-filled area.
        DWORD       dwStatusImmune; // Status immunities.
        BYTE        bPad10[10];     // 0-filled area.
        WORD        wPad11;         // Always FFFF.
        BYTE        bPad12[20];     // Final padding.

    }   * pff7abPlayer = lpvBuffer; // Cast the buffer to this type.

    // Check the fastest things first.
    if ( iSize < sizeof( FF7_BPlayer ) ) { return 0; }

    // Put the non-zero check first because empty areas filled with
    //  zeros are common.   
    if ( pff7abPlayer->wPad11 != 0xFFFF ) { return 0; }
    if ( pff7abPlayer->bCharID > 13 ) { return 0; }
    if ( pff7abPlayer->bLevel > 99 ) { return 0; }

    if ( pff7abPlayer->bPad1 != 0 ) { return 0; }
    if ( pff7abPlayer->wPad2 != 0 ) { return 0; }
    if ( pff7abPlayer->wPad3 != 0 ) { return 0; }
    if ( pff7abPlayer->dwPad5 != 0 ) { return 0; }
    if ( pff7abPlayer->dwPad6 != 0 ) { return 0; }
    if ( pff7abPlayer->wPad7 != 0 ) { return 0; }
    if ( pff7abPlayer->dwPad8 != 0 ) { return 0; }


    // Secondary checks.
    if ( pff7abPlayer->dwCurHP > pff7abPlayer->dwMaxHP ) { return 0; }
    if ( pff7abPlayer->wCurMP > pff7abPlayer->wMaxMP ) { return 0; }

    if ( (pff7abPlayer->bOrder & 0x0F) != 0x08 ) { return 0; }

    // Last detail.
    //  bPad12[2] should be 0x08.
    if ( pff7abPlayer->bPad12[2] != 0x08 ) { return 0; }


    return sizeof( FF7_BPlayer );
}

VOID FF7BPlayerSearchSetup( INT * piDataSize, INT * piAlign, CHAR ** ppcCallback, CHAR ** ppcDecoder ) {
    (*piDataSize) = sizeof( FF7_BPlayer );
    (*piAlign) = 4;
    (*ppcCallback) = "FF7BPlayerSearch";
}




// =====
// The ultimate Final Fantasy VII search!  Search for everything we know how to find (well, everything I have time to write)!
INT FF7Search( LPVOID lpvAddress, LPVOID lpvBuffer, INT iSize ) {
    INT iNewSize;

    // Is this an accessory?
    if ( iNewSize = FF7AccSearch( lpvAddress, lpvBuffer, iSize ) ) { return iNewSize; }

    // Is this an armor?
    if ( iNewSize = FF7ArmorSearch( lpvAddress, lpvBuffer, iSize ) ) { return iNewSize; }

    // Is this a player loaded into battle?
    if ( iNewSize = FF7BPlayerSearch( lpvAddress, lpvBuffer, iSize ) ) { return iNewSize; }

    return 0;
}

VOID FF7SearchSetup( INT * piDataSize, INT * piAlign, CHAR ** ppcCallback, CHAR ** ppcDecoder ) {
    (*piDataSize) = 0;      // Items are of variable size.
    (*piAlign) = 4;
    (*ppcCallback) = "FF7Search";
}




This showcases how to use structures and then perform sanity checks on their members to detemine areas in RAM that hold instances of those structures.

First you have to actually study the game to figure out its structure layouts.
Once you have done that, you can recreate the structures in your own search functions as shown above and then use that to easily verify the data.

You don’t have to understand every member in the structures, as you can see from above.



L. Spiro
User avatar
L. Spiro
L. Spiro
 
Posts: 3129
Joined: Mon Jul 17, 2006 10:14 pm
Location: Tokyo, Japan

Nice

Postby auronxdead » Tue May 20, 2008 6:15 pm

Wow! nice going L.Spiro Lol
You figured im guessing 100% sure you did ;)

Auronxdead
Funny! Joke!!
Grampa:Hey Stan ever made love to a man?
Stan: No way....
Grampa:Aww.... =(
Stan: God darnit pull up your pants already!!
User avatar
auronxdead
Acker
 
Posts: 53
Joined: Sat May 17, 2008 7:25 am
Location: Hueco Mundo

Re: Final Fantasy® VII Searches

Postby Foxx » Mon Dec 28, 2009 10:14 pm

dont understand what are you talking about Sir L.Spiro..im newbies here..sory disturb~
Foxx
I Have A Few Questions
 
Posts: 7
Joined: Mon Dec 28, 2009 9:53 pm


Return to Script Searches

Who is online

Users browsing this forum: No registered users and 0 guests