Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - Maki

Pages: [1] 2 3 ... 22
Damn, that's really great. There's no way to export all in one click, yet I'll try to do my best to do it asap.
New processed images:

Misc. Tools / Re: [FFXV PC] Hammerhead, EARC archiver
« on: 2018-12-03 08:26:30 »
Hi Colly. Sorry for replying after such a looong time. Do you know if Hammerhead 1.4 works with Ep. Duscae and Platinum Demo? I am currently modding those two demo. Are you in the FFXV hacking discord ?
You may want to take a look here:

That upscale is extremely precise! I love it

Completely unrelated / Re: Final Fantasy VIII Mobius event
« on: 2018-12-01 12:39:56 »

it's fully 3D

so I've been struggling for a day about playing audio.dat sound effects internally/ converting them without using 3rd party tools like Audacity or ffmpeg- tried asking some VIPs here but they didn't answer so I had to came up with it myself:

So, FF7 and FF8 use audio.dat + audio.fmt. It's called an Microsoft audio chunk system and was used in XAudio2. You can find the documentation here:

There are several methods to start. First one is to do what Qhimm originally used thanks to publishing source code of FF8Audio. Before we do anything let's first read the FMT content. Sample code is:

Code: [Select]
private struct SoundEntry
            public int Size;
            public int Offset;
            public byte[] UNK; //12
            public byte[] WAVFORMATEX; //18
            public ushort SamplesPerBlock;
            public ushort ADPCM;
            public byte[] ADPCMCoefSets; //28

        private struct WAVEFORMATEX
            public ushort wFormatTag;
            public ushort nChannels;
            public uint nSamplesPerSec;
            public uint nAvgBytesPerSec;
            public ushort nBlockAlign;
            public ushort wBitsPerSample;
            public ushort cbSize;

        private static SoundEntry[] soundEntries;
        public static int soundEntriesCount;

internal static void DEBUG_SoundAudio()
            string path = Path.Combine(Memory.FF8DIR, "..\\Sound\\audio.fmt");
            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            using (BinaryReader br = new BinaryReader(fs))
                soundEntries = new SoundEntry[br.ReadUInt32()];
                fs.Seek(36, SeekOrigin.Current);
                for (int i = 0; i < soundEntries.Length-1; i++)
                    int sz = br.ReadInt32();
                    if(sz == 0) {
                        fs.Seek(34, SeekOrigin.Current); continue; }

                    soundEntries[i] = new SoundEntry()
                        Size = sz,
                        Offset = br.ReadInt32(),
                        UNK = br.ReadBytes(12),
                        WAVFORMATEX = br.ReadBytes(18),
                        SamplesPerBlock = br.ReadUInt16(),
                        ADPCM = br.ReadUInt16(),
                        ADPCMCoefSets = br.ReadBytes(28)
            soundEntriesCount = soundEntries.Length;

After grabbing the content of FMT into the array of struct we can work it here on many different ways:

1. Qhimm WAVE header building method: (if you want only to repair the header for 3rd party player)

ADPCM 4 bit is normally headerless and everything is saved into FMT, however that's still not enough for normal player to be able to play it. We need to build the WAVE/RIFF header:
Code: [Select]
                fs.Seek(soundEntries[soundID].Offset, SeekOrigin.Begin); //seek to raw buffer location in audio.dat thanks to audio.fmt pointer
                List<byte[]> sfxBufferList = new List<byte[]>(); //this will be used as an dynamic array, I'm just too lazy
                sfxBufferList.Add(Encoding.ASCII.GetBytes("RIFF")); //let's start with magic RIFF
                    (soundEntries[soundID].Size + 36)); //now the size read from FMT + 36
                sfxBufferList.Add(Encoding.ASCII.GetBytes("WAVEfmt ")); //now the WAVEfmt (there's a space, so it takes eight bytes)
                    (18 + 0)); //eighteen
                sfxBufferList.Add(soundEntries[soundID].WAVFORMATEX); //now encode full WAVEFORMATEX struct packed
                sfxBufferList.Add(Encoding.ASCII.GetBytes("data")); //now add 'data' in ascii
                sfxBufferList.Add(BitConverter.GetBytes(soundEntries[soundID].Size)); //now put the size again from FMT
                byte[] rawBuffer = br.ReadBytes(soundEntries[soundID].Size); //obviously read audio.dat
                sfxBufferList.Add(rawBuffer); //and add it on the bottom
                byte[] sfxBuffer = sfxBufferList.SelectMany(x => x).ToArray(); //now cast every byte in byte list to array

sfxBuffer now contains correct ADPCM WAVE file you can save and play in your favourite software.

2. My ADPCM->PCM + play method using NAudio: (for actually converting the file + playing in new thread)
I tested many different libraries, I mean it- Bass, CSCore, libZplay and some I even forgot about. None works with ADPCM, however NAudio does it. Grab NAudio release from github page (google it). This time it's super easy-
Code: [Select]
using NAudio;
using NAudio.Wave;

internal static void PlaySound(int soundID)
            if (soundEntries == null)
            if (soundEntries[soundID].Size == 0) return;
            using (FileStream fs = new FileStream(Path.Combine(Memory.FF8DIR, "..\\Sound\\audio.dat"), FileMode.Open, FileAccess.Read))
            using (BinaryReader br = new BinaryReader(fs))
                fs.Seek(soundEntries[soundID].Offset, SeekOrigin.Begin);
                GCHandle gc = GCHandle.Alloc(soundEntries[soundID].WAVFORMATEX, GCHandleType.Pinned); //it's not recommended way in C#, but I'm again- lazy
                WAVEFORMATEX format =  (WAVEFORMATEX)Marshal.PtrToStructure(gc.AddrOfPinnedObject(), typeof(WAVEFORMATEX));
                byte[] rawBuffer = br.ReadBytes(soundEntries[soundID].Size);

                //passing WAVEFORMATEX struct params makes playing all sounds possible
                RawSourceWaveStream raw = new RawSourceWaveStream(new MemoryStream(rawBuffer), new AdpcmWaveFormat((int)format.nSamplesPerSec, format.nChannels ));
                var a = WaveFormatConversionStream.CreatePcmStream(raw);
                WaveOut waveout = new WaveOut(); //you have to use new instance for EVERY sound played
                waveout.Init(a); //as said in documentation- init is supposed to be called once.

3. Forcing playing with PCM codec
Totally not recommended- you'll get harsh and all the noise. However it requires no codec or libraries. I'll be using default sound effect player of MonoGame framework.
First get the default raw buffer without header as-is in audio.dat. See the code above to get byte[] rawBuffer. Now:
Code: [Select]
SoundEffect se = new SoundEffect(sfxBuffer, 22050, AudioChannels.Mono);
se.Play(1.0f, 0.0f, 0.0f);
22050Hz + mono are the only parameters that makes playing ADPCM forced sound as natural as possible

>gaining funds for creating fan projects based on someone's IP
>knowing that SE always kills fan projects
>kickstarter having only description of what it's going to be
>title and Unreal Engine is what's all about the game
>no serious art, screenshots, promotion
>made by one person
>community manager as someone in charge of SE
>goal of thousands of dollars for project that can get cancelled so fast

EDIT: It indeed sounds brutal, but keep on progressing! We are all on the same boat which is FF addiction. I still wish you best, yet be prepared for what I tried to tell you

I'm being able to see the codes inside the places, how can I see the encounters in worldmap?
Open wmset>  edit encounters

Screens in Polish, name in English. 😱
Glad y'all sorted it out

ScpToolkit works well for me.

Completely unrelated / Re: Don't be shy - Photos
« on: 2018-10-05 20:19:56 »
well strawberries, here I am in the middle holding some beer

Here I am browsing Qhimm forums:

and here... oh well

and yes- they still ask me for an ID at shop, all my friends look their age, but I'm like stuck at 16

Hello again!
Some time ago I received an e-mail if I might be looking back at that obfuscated/crypted assembly:

1. Anti debugger privileges was my paranoid anti-malware software
2. mobiusff.exe is C++ 64 bit Unity assembly
3. The assembly-csharp.dll IS NOT loaded as library (via loadlibrary)
 3a. I hooked every single I/O operation to actually find what makes it to parse Assembly-csharp.dll. See image below

Assembly-csharp.dll is broken on purpose to not be available to anything that manages symbols from DLL other than specific software written to ignore such details. I'm going to find the code location inside memory and see what I could do

0x2EC- this whole file is completely crypted... Normal PE is fine, but the whole .NET is completely ciphered

MonoManager::LoadAssemblies(dynamic_bitset)+184 -> loads the .DLL (and probably parses it/ RAX contains struct with assembly pointers)
MonoManager::LoadAssemblies(dynamic_bitset)+191  call    cs:mono_assembly_get_image

I'm close:
These are strings from pre-loaded assembly image from struct:

pointer 2:

Pointer 3:

It's not full assembly (there's no i.e. BSJB), but it's already deciphered/decrypted so looks like MonoManager::LoadAssemblies(dynamic_bitset)+184 is where I need to go deeper (it's before I/O and after decipher)

I got it. I'm soon to rebuild the assembly

AF3DN.P - This file contains functions for Steam mods including boosters. FFVIII load this file and overwrite it's functions with the loaded file content. You shall start searching there specifically. It's normal PE or DLL afair.

You are looking for so-called "code caves". Quick scan for memory in runtime yelds these adresses of at least 64 bytes of memory padding that you can use for code injection:

Code: [Select]

These are applicable for FF8 2000 PC release with 1.1 patch. There's no big difference in Steam version for that.
In future you can use Cheat Engine>Memory View>Tools>Scan for code caves

As for resetting the counter, I'm a little less sure of where to put it but was thinking the battle results screen as even when escaping that screen tends to come up. Does anyone know where that section starts from?

The easiest what comes to my mind is checking if engine_state == 8 (this is battle mode). If not, then reset counter, if yes, then ignore. Anyway, here are the main function to note:
FFBattleInitSystem (called from FFModuleHandler and FFBattleTransitionModule)- it's at 0047CE00 (0007CE00). More specifically:

Code: [Select]
FFBattleInitSystem+1E   66 83 3D C6 8F CD 01 08                 cmp     _StateGlobal, 8where _stateGlobal (global variable) is at 01CD8FC6 in .data in-memory

There's also:
FFBattleExitSystem called from FFModuleHandler and FFBattleTransitionModule that sets previous renderer screen-space and is located at:
0x0047CEE0 (0x0007CEE0)

About the R/W, it's true, but only if you need to store some local. Here are some 64 bytes regions with R/W: (but use them rather for storing what you need instead of code)
Code: [Select]
00B6D0A8 <- I recommend this one, it's section between imports for PE and strings that are allocated on 256 bytes

It's live!

Colours are correct now with dynamic replace. Tested with one-sprite package, first replace, last replace, n replace and in-game replace. Everything looks great. Have fun!

Great news!
I managed to code fully working replace with sizing (you can import high resolution images, I tested replacing 512x512>1024x1024 and 512x256> 128x64 and it works really great! Although the game engine doesn't sctretch the assets (at least the ones I tested). Anyway, here's current github page:
it's still WIP, there are some color issues with dynamic replace (dynamic is when you change .PNG resolution) and I still haven't tested it on one sprite only FLB files.

I have a load of work at job so I'll try to do it asap

copy of game? Only for testing as I'm not sure the pointers are enough for modifying the file. Anyway, here's the entry version of the tool that does unpacking transparent .PNG graphics from .FLB, do not click on replace, it does nothing atm. I'm sharing this in this non-completed state as you may start working on the graphics now while I'll be working out the repacking:

Compiled binary + source code so far:
Just go to bin>release and you'll find exe there

That's unusual, but if that's the author intention then ok, send it over PM.
File format so far:
Code: [Select]
char[8] FLBD0101;
uint IMCHpointer;
uint unk;
padding[8]; //?
uint UnknownSHCHpointer; //0x28 + this
uint UnknownSPCHpointer; //0x28 + this
uint UnknownBTCHpointer; //0x28 + this
uint UnknownANCH0pointer; //0x28 + this
IMCH imch;

Code: [Select]
char[4] IMCH
uint IMCHsize; //including this + IMCH header
uint CountOfFrames; //This is global count of pointers to graphics;sprites;frames in file. It means one FLB can contain many graphics
uint SpritePointer[CountOfFrames]; //first one usually points to 0x00, so just: IMCHpointer+IMCHsize+pointer;

Code: [Select]
byte[20] unknown_maybeChecksum?;
uint Unknown;
ushort width;
ushort height;

Oh, ok. I got it! Updated the structure

Example summon_00f_bg1_full.flb is 256x512 and raw texture data is 524288 bytes;
256x512 is 131072; 393216 is dividable by:
Code: [Select]
Size:   1
Size:   2
Size:   3
Size:   4 <--
Size:   6
Size:   8
Size:   12
Size:   16
Size:   24
Size:   32
Size:   48
Size:   64
Size:   96
Size:   128
Size:   192

131072 * 4 = 524288;
So this is for sure 32 BPP data, therefore:

Are these colors ok?

As far as I see:
1. Inject upgraded/upscaled texture data
2. Change width/height
3. Tweak SHCH; SPCH; BTCH and ANCH0 pointers
4. Tweak IMCH pointers to texture data that got changed due to different imageSize after the pointer to changed textureData
5. Well, looks like that's all. :-)

Diablos looks great! (ARGB -> BGRA/ABGR)

Please provide any information you have and a sample file.

This looks awesome Maki, do you have a tutorial on how to set it up, do you need to download unity etc
Oh right, sorry. I'll make sure to write the tutorial to set-up everything ASAP

porting FF8 to PS4 aswell, via Custom UNITY engine?
So... I'm working in gamedev industry and have access to official PS4+XOne SDK*, but even with that it's not so easy. For Unity you need to have full commercial license. It's better for XNA however, as you need only the target file. Anyway, everything's possible.

*but please do not ask me for anything about it. :(

This is true act of bored person:
OpenVIII - the FF8 engine set:

Just two implementations of FF8 engine that works ONLY on real VIII files meaning you wouldn't even run it without Steam release of VIII or slight code change.

In the package you will find:
OpenVIII - This is Unity project, that provides:
  • real-time battle 3D rendering with textures
  • basic field rendering with camera setup
  • all LZSS, field archive and whole core

FF8 - This is Monogame project, that provides:
  • real-time battle 3D rendering with textures that renders face one-by-one considering the CLUT (closest to original fan-made battle stage rendering ever made)
  • basic field rendering
  • real DirectMidi support for direct DLS and SGT music
  • Movie player (unfortunately not Bink wrapping, but casual MPEG4 without sound)
  • all LZSS, field archive and whole core

Use it to learn, use it for your own projects, use it to listen to music or view 1:1 stages with FPS camera, whatever. I simply don't care.

Before you proceed with anything make sure you have Final Fantasy VIII steam version installed (or 2000 PC version if you can do basic coding)

FF8 - XNA/MonoGame:

1. You may need to install MonoGame for VisualStudio. You can do it without any problems at: ; Just make sure to download DEVELOPMENT build for Visual Studio instead of official releases (they are quite outdated)
2. After grabbing MonoGame you'll be able to open Visual Studio 2015 (minimum) project without any problems. Just open FF8.sln with Visual Studio
3. Open Game1.cs- this is entry-point class. You can uncomment line 26 at init_debugger_Audio.DEBUG(); to enable DirectMusic
4. Open Memory.cs and take a look at lines 37 and 38. You'll understand the drill. Set the path there to your lang-en catalogue of FF8 or change it to e.g. lang-fr, doesn't matter, files should be there. Make sure path ends with '\' (lazy programmer I am)
5. DONE! You'll enter automatically into field mode. Use F keys to change modes:
F2 - change module to battle and set to next stage
F3 - Next music
F4 - change module to field and set to next field
F5 - same as above but gets back to previous field ID
Battle stage:
Movement mouse; WSAD translation
ALT+F4 ;_;

Python code for getting 'objects' element, also contains structure data:

Code: [Select]
import sys
import struct

filePath = sys.argv[1]

f = open(filePath, 'rb')
xmb2 =
eof = struct.unpack('L',[0]
flags = struct.unpack('H',[0]
version = struct.unpack('H',[0]
rootElement = struct.unpack('L',[0],1) #xmbDocument is casted now to XmbElement

xmb2Element_elementStartOffset = struct.unpack('L',[0] #v6
xmb2Element_attributeStartOffset = struct.unpack('L',[0]
xmb2Element_elementCount = struct.unpack('H',[0]
xmb2Element_attributeCount = struct.unpack('H',[0] >> 8,1) #going back to XMB2Element root
AbsoluteXmb2ElementRoot = f.tell() # &v3->elementStartOffset_
IndexPointer = 0 #v4
SignedPointer = AbsoluteXmb2ElementRoot + 4 * IndexPointer + xmb2Element_elementStartOffset, 0)
SignedPointerValue = struct.unpack('i',[0]
v7 = AbsoluteXmb2ElementRoot + (4*IndexPointer) + xmb2Element_elementStartOffset + SignedPointerValue
#(char *)(v7 + *(_DWORD *)(v7 + 4) + 4i64);
v8Pointer = v7 + 4, 0)
v8PointerValue = struct.unpack('I',[0]
_ = v7 + v8PointerValue + 4,0)
#v9 = &v8[*(_DWORD *)v8];
v8 = struct.unpack('i',[0],1)
v8Pointer = f.tell()
v9 = v8Pointer + v8, 0)
v9Pt = struct.unpack('B',[0]
if v9Pt == 1:, 0)
v10Pt = struct.unpack('I',[0]
v10 = v9+v10Pt+5,0)
objectName ='\0')[0]
print('Index: ' + str(IndexPointer) + ': ' + objectName)

Just a quick hint- FFXV_s.exe base is dynamic, therefore patch:
Code: [Select]
ffxv_s.exe:0x1EE = 0x20 (replacing 0x60, 2nd bit from 1 to 0)
this will disable ASLR and base image on 0x140000000

any further notes I'll write here will consider 0x140000000 as the base instead of 0x00007FF*

If you're using IDA make sure to rebase the database last time by Edit>Segment>Rebase, for CE or Olly it doesn't matter, anyway I'll try to post relative addresses like ffxv_s.exe+0xFFFF like in CE style

Okay, about XML20 (exml):
Code: [Select]
00000000 identifier dd ?
00000004 fileSize dd ?
00000008 flags dw ?
0000000A version dw ?
0000000C rootElementOffset dd ? <-- relative to root

Getting elements (useful for offset strawberries):
Code: [Select]
SQEX::Luminous::Xml::Xmb2Element::GetElementByName(Xmb2Element el, char* name);example:
000000016459061C SQEX::Luminous::Xml::Xmb2Element <elementStartOffset_: 0B44h, attributeStartOffset_: 0F58h, elementCount: 1, attribCount: 1h>

int64 i = 0;
var v7 = &xmb->elementStartOffset + 4* i + xmb->elementStartOffset + *((xmb->elementStartOffset)+&xmb->elementStartOffset)
Let's simplify it: we just jump to relative pointer of i * 4 of pointer address of XMB document + element start offset, like this:
Code: [Select]
uint64 pointer = XMBdocument + elementStartOffset + i*4;
uint64 v7 = pointer + *(pointer);

Now the unknown pointer:
char* v8 = v7 + (*(v7 + 4)+4);
if v8 is not null, then treat as array of objects:

v10 = v9 + *(v9+5) + 5

The abstraction level of everything here is so high... struct with struct with struct, that's not assembler-level friendly.

Code: [Select]
0: reference
1: entities_.common_textures_list
2: entities_.initialize1_list
3: entities_.system_no_autoload
4: entities_
5: hasTransform_
6: bool
7: position_
8: float4
9: rotation_
10: scaling_
11: float
12: canManipulate_
13: sourcePath_
14: common/initialize1.ebex
15: string
16: name_
17: dff7c814-9313-45a9-b8fd-5fc7ca670db7
18: isTemplateTraySourceReference_
19: isShared_
20: startupLoad_
21: object
22: initialize1
23: SQEX.Ebony.Framework.Entity.EntityPackage
25: filePath_
26: textures/ebony_required_textures.txt
27: isAutoLoad_
28: common_textures_list
29: Black.Entity.Data.EarcResourceList
30: common/initialize1_list.txt
31: initialize1_list
32: common/system_no_autoload.txt
33: system_no_autoload
34: objects
35: package

Looks like it's raw data that is treated via struct. Currently it looks like the pointers and attribute+element count is stored in the middle of the file.
ai/commonai/commontpslibrary.exml ->
debug::63140000 = XMB2
debug::6314016C = XMBDocument

Looks like EXML contains many XMBDocuments

I just got an e-mail from "Haggy" with an amazing report- due to mistake SquareEnix uploaded debug build of FFXV with PDB !!!
Whole build with pseudocode is available to download on the bay, just search for "Final Fantasy XV Debug Symbols".

Full debug information with even troubleshooting is there xD

Important functions (changed argument names for clarity):
Code: [Select]
void ** SQEX::Luminous::AssetManager::LmArcFileSystem::OpenFile (LmArcFileSystem *this, LmAssetID *i_id, LmEAssetLoadPriority priority)

File read:
SQEX::Luminous::AssetManager::LmArcFileSystem::ReadFile -> determines if compressed or not by LmArcInterface::FindAssetInfo ->

int64 SQEX::Luminous::AssetManager::LmArcFileSystem::ReadCompressed(LmArcFileSystem *this, FileSystemEntry *i_pFileEntry, ArcAssociation *i_pArchive /* this one is archive name in 80%*/, void *o_pAddress, unsigned int i_length, void **io_asyncHandle, LmEAssetLoadPriority priority, SQEX::Luminous::Core::IO::IFileDevice::FileAttribute attribute)

struct LmArcInterface::ArcAssociation (this is what we know so far despite being a copy-of AssetManager:LmAssetKey):

Code: [Select]
QWORD entry ; offset // It's in fact in code as LmArcCatalogShortEntry
DWORD arcMountIndex
BYTE UNK ; undefined
BYTE UNK ; undefined
BYTE UNK ; undefined
BYTE UNK ; undefined

Code: [Select]
QWORD nameTypeHash    dq ?
QWORD dataStart
std::string name
std::string pAbsolutePath
DWORD originalSize
DWORD compressedSize
USHORT flags
BYTE localizeType
BYTE localizeLocale
SHORT encryptKey

Visual Studio works as expected:

General discussion / Re: Rinoa in Dissidia !
« on: 2018-07-18 20:05:30 »
Is Dissidia easy to rip? Wish to play with her model (nothing naughty!)

Pages: [1] 2 3 ... 22