News:

11 March 2016 - Forum Rules

Main Menu

[Help] Repositioning a single sprite.

Started by sics, September 15, 2019, 01:48:59 PM

Previous topic - Next topic

sics

 Hello, I was working to create a new translation for the title screen of DBZ III - Ressen Jinzou Ningen (J) [!]. Nes, but when I adjust the position of the sprite of the dragon sphere (in the logo) The game is no longer compatible with the VirtuaNES emulator :'(



My goal is to edit the X axis located at address 62c3 with the number A8, but my limitations prevent me from finding the source of the problem (The original value is B1).

I attach the patch in question :thumbsup:
Linktree  | Better a small finished project than a thousand giant ideas stuck in your system.

Cyneprepou4uk

#1
I can look into it a bit later. While I'm away from my pc, tell me, is it compatible with mednafen emulator?

September 15, 2019, 04:08:18 PM - (Auto Merged - Double Posts are not allowed before 7 days.)

I've done a bit testing, and here is my verdict - virtuanes hates when you change even a single byte in this rom and refuses to emulate it. Must be some sort of mapper checksum failure or something. Throw that emulator in a garbage.

sics

 I guess I can make a separate patch for VirtuaNES, regarding its compatibility, it works correctly in the rest of emulators that support the game.

Anyway I feel very sorry to do it this way, so if someone can help shed light on this issue I would be very grateful.

The optimization of the data is really ingenious, and the starting point of the sprite is in the center of the screen, maybe its position depends on some other variable that I am not able to identify

On the other hand, thank you very much for your help Cyneprepou4uk! :thumbsup:
Linktree  | Better a small finished project than a thousand giant ideas stuck in your system.

zzdd

I never thought that I would be talking about NES modding, but your question got me curious.

After reading a couple of hours (with testing), your emulator issue is related to some sort of validation of BANDAI 24C02 mapper (16-5)(which only 6-7 games have it) for the PRG ROM data. So what can be done:
1. Change emulator as Cyneprepou4uk already suggested.
2. Wait for an update (or hack the emulator to bypass the PRG ROM validation)
3. Only modify the CHR ROM data (graphic data for the ppu or something like that)
4. Decompile (reverse engineer) the PRG ROM data and compile it for a more generic mapper or circuit (may be 04)(I believe this can be quite difficult, I could be wrong).
Support this site on Patreon

nesrocks

If virtuanes does the check through CRC I've got this EXACT same problem and would appreciate to know if you managed to do the reverse CRC and how.

zzdd

#5
"still taking me to school"
Yes nesrocks is right. After reading the VirtuaNes src, I found this:

DWORD crc = nes->rom->GetPROM_CRC();

        //Some more if's

if( crc == 0x09499f4d ) { // Dragon Ball Z 3 - Ressen Jinzou Ningen(J)
nes->SetIrqType( NES::IRQ_HSYNC );
eeprom_type = 1;
}

PRG_ROM goes from 0x10 to 0x40010.

So if you make your modded PRG_ROM to have this CRC-32: "0x09499f4d", your hack will run in that emu.

Which goes to nesrocks problem. A cryptography problem...

There are already solutions (done by others):
https://github.com/madler/spoof
https://github.com/rr-/CRC-manipulator


Its really late here like 2am, but here is an explanation (from 2 other ppl 4 years ago):
Spoiler
Sorry I was not clear. All operations described below are done in GF(232).
P * x32 mod crc_poly is the remainder of (P shifted 32 bits to the right) after dividing by the CRC polynomial, which is how CRCs are computed).
inverse(x32) is the multiplicative inverse of x32 mod crc_poly. Multiplicative inverse means x32 * inverse(x32) mod crc_poly = 1.
Maybe there is another way but here is an example:
M1 = 'The quick brown fox jumps over the lazy dog'
M2 = 'Another string'
CRC32(M1) = 414fa339
CRC32(M2 || 00004 bytes) = 80bd6d26
XOR them together and undo the bitreverse: K = f8734f83 (note that XORing two bit inverted values will cancel the bit inverse)
The multiplicative inverse of x32 = cbf1acda.
Now P = K * inverse(x32) mod crc_poly
= f8734f83 * cbf1acda mod 104C11DB7
= 5d9fe0f5.
Reverse each byte since CRC32 works with LSB of each byte first: baf907af.
Verify that CRC32(M2 || baf907af) = 414fa339.



bontchev
Sorry, I'm still lost. :(
    M1 = 'The quick brown fox jumps over the lazy dog'
    M2 = 'Another string'
    CRC32(M1) = 414fa339
    CRC32(M2 || 00004 bytes) = 80bd6d26
So far, so good.
    XOR them together and undo the bitreverse: K = f8734f83 (note that XORing two bit inverted values will cancel the bit inverse)
Sorry, where did f8734f83 come from? 414FA339 XOR 80BD6D26 is C1F2CE1F. Even if we invert that, we get 3E0D31E0.
Edit: Given that I have misunderstood what you meant by "invert" (see below), we have:
C1F2CE1F hex is 11000001 11110010 11001110 00011111 binary. Reversing the order of bits (considering them as a continuous stream of bits, not on a byte basis), we get 11111000 01110011 01001111 10000011, which is F8734F83 hex. Is that what you meant by "undo the bit reverse"?
    The multiplicative inverse of x32 = cbf1acd
How did you get that from the numbers so far?
    = f8734f83 * cbf1acda mod 104C11DB7
Where did 104C11DB7 come from? Is that the generator polynomial for this particular CRC-32?
    = 5d9fe0f5.
I don't get it... :( According to my hex calculator, F8734F83 * CBF1ACDA is C5EDFC5BC6F0B98E. Mod 104C11DB7 results in 115CF38C? Am I misunderstanding what you mean by the operations "*" and "mod"?
    Reverse each byte since CRC32 works with LSB of each byte first: baf907af.
Again, I don't follow. If you invert each bit of 5D9FE0F5, you get A2601F0A...
Oh, wait, I think I got this part. By "reverse" you mean re-order; not flip the contents. So, we have
5D9FE0F5, which is 01011101 10011111 11100000 11110101 binary. You reverse the order of bits in each byte, resulting in 10111010 11111001 00000111 10101111, which is BAF907AF hex.



supersaw7
I should really improve my explaining skills :)
reverse = reverse the order of the bits, bit inverse = bitwise not.
0x104C11DB7 is the CRC32 polynomial, with the explicit x32 coefficient (most tables omit that).
[close]
Support this site on Patreon

nesrocks

#6
Glad that was the thing :) I'm sorry to maybe hijack the thread, but since I'm not using C or anything common really, I would love an explanation of the math behind step "four" of this tutorial. Any such luck?

edit: that checksum manipulator is incredible, it might be the second best thing other than knowing the math behind step 4 of the tutorial, so thank you very much for that.
edit2: you may have led me to learn that GM allows external programs to be run with args through a code. I'll need to test this.
edit3: I see your edit. Yes, I had already seen that but it doesn't explain much. Inverse(x32) make it sound like he is flipping the most significant bit (32 from the right) which obviously isn't it. Another thing he said is that this means shifting "P" 32 times to the right which also can't be true because that would always give zero as a result. I'm going to call this solved for now and use the command line program, thanks!

Cyneprepou4uk

Thanks for the links, they will come in handy someday.

Man, why those github developers never upload an exe as well. They are assuming everyone has a compilator, or linux, or what's up with that?

sics

zzdd
First of all, thank you very much, when I am in the learning period it is very important for me to know that the problem was not caused by my mistake. On the other hand it still escapes from me how to modify the PRG_ROM of a game, but I will certainly investigate it  :thumbsup:

nesrocks
I am very happy that I have hijacked my post, the result is very enriching and that tool is certainly invaluable

Cyneprepou4uk
The page if you have a compiled version ;)
Linktree  | Better a small finished project than a thousand giant ideas stuck in your system.

zzdd

#9
First, sics:

Nes rom (yes the .nes file), has sections:
-Header 16 bytes
-Optional whatever (the current rom we are talking doesn't have this)
-PRG Rom data (in this rom is 0x40000 bytes long)
-CHR Rom data (another xxxx bytes long)
-Optional (or not dunno) more whatever

You need to dump as a separate binary file from 0x000010 to 0x040010 (here is your B1-> A8 mod at 62b3)

You need to "tweak" this entire binary file, for crc-32 this can be done by modifying the last 4 bytes (if they are important for the PRG rom, it could be a issue)(first set them to zero, do all the stuff explained above and get your new 4 bytes).

Now with the tweaked file (0x40000 byte long), put it back in the rom file. In this case you will modify 62c3 and 4000c-4000d-4000e-4000f (this last 4 bytes will look like a random padding).


Second, nesrock:
Here, my explanation (based on the already given explanation):
Spoiler
M1 = 'The quick brown fox jumps over the lazy dog'
M2 = 'Another string'
CRC32(M1) = 414fa339
CRC32(M2 padded with 0x00 0x00 0x00 0x00) = 80bd6d26
414fa339 XOR 80bd6d26 = C1F2CE1F
Flip(C1F2CE1F)=f8734f83
The multiplicative inverse of x^32 for CRC32 is always = cbf1acda.
https://en.wikipedia.org/wiki/Finite_field_arithmetic
https://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
Use a GF(pn) calculator(also called the Galois field)
Cuz 100000000*cbf1acda mod 104C11DB7 = 1
https://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplication
Then:
f8734f83 * cbf1acda  mod 104C11DB7 = 5d9fe0f5.
Reverse each byte since CRC32 works with LSB of each byte first: baf907af.
By "reverse" you mean re-order; not flip the contents. So, we have
5D9FE0F5, which is 01011101 10011111 11100000 11110101 binary. You reverse the order of bits in each byte, resulting in 10111010 11111001 00000111 10101111, which is BAF907AF hex.
Verify that CRC32(M2 padded with baf907af) = 414fa339.
[close]

Update:
With what Cyneprepou4uk said (about last 6 bytes), i make this .py file:
Spoiler
import BitVector as bv
import binascii

#pip install bitvector, if needed.

def reverseByteWise(x):
    y1, y2, y3, y4 = (x & 0xFFFFFFFF).to_bytes(4, 'big')
    y1_r = int('{:08b}'.format(y1)[::-1], 2)
    y2_r = int('{:08b}'.format(y2)[::-1], 2)
    y3_r = int('{:08b}'.format(y3)[::-1], 2)
    y4_r = int('{:08b}'.format(y4)[::-1], 2)
    return int.from_bytes([y1_r, y2_r, y3_r, y4_r], byteorder='big')

def addPRGSection(data,SIZE=16384):
    return data+b'\x00'*SIZE

def fixPrgCRC(infile,infile2,outfile,ADDSEC=True):
    poly = bv.BitVector(intVal = 0x104C11DB7) # "standard" CRC32 polynomial
    inv = bv.BitVector(intVal = 0x100000000).gf_MI(poly, 32)

    with open(infile,'rb') as file:
        data=file.read()

    original_crc=binascii.crc32(data)

    with open(infile2,'rb') as file:
        data2=file.read()

    if ADDSEC:
        data_modded=addPRGSection(data2)
    else:
        data_modded=data2+b'\x00'*4

    padded12_crc=binascii.crc32(data_modded)

    xored= original_crc ^ padded12_crc
    flipped=int('{:32b}'.format(xored)[::-1], 2)
    p_reversed = bv.BitVector(intVal = flipped).gf_multiply_modular(inv, poly, 32)
    p=reverseByteWise(int(p_reversed.getHexStringFromBitVector(),16))

    if ADDSEC:
        data_modded=addPRGSection(data2,16380)
    else:
        data_modded=data2
    data_modded+=p.to_bytes(4, 'big')
    with open(outfile,'wb') as file:
        file.write(data_modded)

    print("Original file CRC: "+hex(original_crc))
    print("Tweaked file CRC: "+hex(binascii.crc32(data_modded)))

def fixRomCRC(infile,infile2,outfile):
    fixPrgCRC(infile,infile2,outfile,False)

def rebuildROM_onlyPRG_noTrainer(infile,infile2,outfile):
    with open(infile,'rb') as file:
        data=file.read()
    sizePRG=int.from_bytes([data[4]], byteorder='big')
    header=data[0:4]+(sizePRG+1).to_bytes(1, 'big')+data[5:16]
    romPRG=data[16:sizePRG*16384+16]
    rest=data[sizePRG*16384+16:]
    with open(infile2,'rb') as file:
        data2=file.read()
    romPRG=data2
    data_modded=header+romPRG+rest
    with open(outfile,'wb') as file:
        file.write(data_modded)


if __name__ == "__main__":
    option=1
    if option==1:
        #Even adding an expansion to PRG bugs VirtuaNes. So it doesn't work.
        #It would be more easy to hack the emu than try to fix this...
        fixPrgCRC("ressen-prg-orig.bin","ressen-prg-modded.bin","ressen-prg-tweaked.bin")
        rebuildROM_onlyPRG_noTrainer("ressen.nes","ressen-prg-tweaked.bin","ressen-modded.nes")
    else:
        #Or just fix the rom crc, it won't work with VirtuaNes cuz need Prg crc
        fixRomCRC("ressen.nes","ressen-modded.nes","ressen-tweaked.nes")
[close]

Still it doesn't work for VirtuaNes...
Support this site on Patreon

Cyneprepou4uk

#10
Actually he can't edit last 6 bytes for new crc, because those are cpu interrupt vectors, like Reset

@sics, that's good, thanks. So I need to check for Releases page then.

nesrocks

Quote from: zzdd on September 16, 2019, 09:13:35 AMThe multiplicative inverse of x^32 for CRC32 is always = cbf1acda.
I imagine that is the case when considering CRC32's default polynomial (which is my case, fortunately). So "inverse(x32)" in this case is just a constant. Wow... Thank you!

Cyneprepou4uk

QuoteStill it doesn't work for VirtuaNes

That's odd. Can I have that patch?

zzdd

Here

Or

Just open the VirtuaNes.exe file (yes the exe) in a hex editor, search for (as hex value):
4D9F4909
You should see 2 hits (at least), then replace both with the modded PRG crc (change byte order), the OP original IPS has this one:
A5B3F339

And forget about fixing the crc.
Support this site on Patreon

Cyneprepou4uk

#14
No, I meant a patch, where you changed 4 bytes (plus a change made by sics with #A8 at 0x62C3), not in the end of the prg rom but somewhere else in it, and it still failed to run on virtuanes even with correct crc. Didn't find it in your link

sics

 New information, based on the declaration of Cyneprepou4uk (which this game does not like to be modified) it occurred to me to try the title screen with the translation for which it is intended.

Now go back to work in VirtuaNES, but ceased to be compatible with puNES, and the official compilation of FCEUX, since in this hack the mapper 16 is changed by the mapper 17.


On the other hand I use to compile VirtuaNES Plus, so I could not find the hexadecimal value given.
Linktree  | Better a small finished project than a thousand giant ideas stuck in your system.

zzdd

Lets explain a bit what each ips does:

-badprg.ips
Makes the modded PRG to have the same CRC as the vanilla PRG (09499f4d). But writes 4 bytes in the last for 4 bytes of the PRG (it won't load in any emu). Is just a bad PRG. Only use for testing purposes.

-expanded.ips (this is the one that didn't work for VirtuaNes)
Similar to -badprg.ips, but here in the NES header PRG size goes from 16 to 17 (so now the PRG is 0x44000 bytes long). I was hoping that adding a 0x4000 zeroed section with the last 4 bytes changed so PRG CRC match with vanilla, could bypass VirtuaNes prg-crc validation. But it just create another bad PRG rom. Only use for testing purposes.

-allcrc.ips
Here the entire rom file is tweaked to match vanilla rom CRC (a69079d4), without increasing the file size (for some reason beyond the scope of this thread, i needed to add 4 zeros to get the 4 bytes for padding). This patch won't work with VirtuaNes since PRG CRC is different from vanilla.

-allcrc-padded.ips
Similar to -allcrc.ips but rom size will increase by 4 bytes in order to fix the rom CRC. This patch won't work with VirtuaNes since PRG CRC is different from vanilla.

The big issue with VirtuaNes is that the emu reads only the PRG, so the size of PRG can't be changed and the last 6 bytes of PRG are important, tweaking the PRG to match the vanilla CRC is more complex (you must use something like spoof and specify what bytes can be used to tweak)

Quote
Now go back to work in VirtuaNES, but ceased to be compatible with puNES, and the official compilation of FCEUX, since in this hack the mapper 16 is changed by the mapper 17.

On the other hand I use to compile VirtuaNES Plus, so I could not find the hexadecimal value given.
Don't change the mapper.
I tried with FCEUX 2.2.3 and it works (it never needed crc fixing)
I tried with puNES and it works (it doesn't need crc fixing)
VirtuaNES Plus, really hard to know which binary exe you have, but i tried this and it had the hex value (4D9F4909) twice.

Remember that every time you mod the PRG (even if its one bit), the crc will change so you will need to update whatever solution you are using to run the ROM in VirtuaNes.
Support this site on Patreon

sics

QuoteVirtuaNES Plus, really hard to know which binary exe you have, but i tried this and it had the hex value (4D9F4909) twice.
Sorry, sometimes I forget that I am no longer using Translhextion and get confused .

QuoteDon't change the mapper.
It is actually the patch is not for me, have asked me to create for use in an existing translation, and in it the mapper 17 as mentioned is implemented.

QuoteI tried with FCEUX 2.2.3 and it works (it never needed crc fixing)
Of course, it is that the truth was fascinated by the way the issue unfolded, even I was researching over other translation attempts to find out if anyone had found a solution.

The closest thing to a solution I found was a multicard that included the same game with a mapper created by Cony Soft the Dragon Ball Z Party 4-in-1.
And although it can locate the PRG (84010-C400F) and CHR (180010-1C0000) I could not do anything with that information.

I think the sensible thing is to accept that VirtuaNES already out of date, and let whoever wants to play this game in the emulator do it through the solution you've shared, or wait for some future update  :thumbsup:
Linktree  | Better a small finished project than a thousand giant ideas stuck in your system.