Leer archivo ROM y obtener información

Iniciado por Meta, 5 Junio 2015, 09:46 AM

0 Miembros y 1 Visitante están viendo este tema.

Meta

Hola:



He hecho un boceto no funcional, que tiene que leer una ROM de una Super Nintendo, en este caso uso el juego Ultimate Mortal Kombat 3. Toda l ainformación que se indica arriba nada más cargar el archivo este programa tiene que mostrarlo. No se la mejor manera de hacerlo. Por ejemplo, en la cabecera ROM del programa aparece el título que encuentra dentro de la ROM. Mirando con este editor hexadecimal gratuito lo he encontrado en la posición de dirección de memoria concretament esta 101C0 muestar el título como indica en la imagen de abajo.



Siempre son de longituda 15 carácteres o bytes contando hasta los espacios en blanco. Así que cualquier ROM debe buscar ese título dentro del juego.



Quiero hacer este programa poco a poco y tome forma, así que abajo les dejo las descargas y hagan pruebas. Pensé en buscar la posición de memoria que casi siempre es el mismo en los 4 MB que pesa el archivo, en otros programas que funciona de maravilla los detecta aunque la posición de memoria sea diferente, no todas las ROM son iguales, así que creo que busca los 15 bytes del título.

El programa original lo descargas aquí que este si es funcional y quiero hacer lo mismo. ¿Por qué iba ahcer lo mismo si ya existe?

La respuesta es que en cada pestaña haré funcione de cada programa para hacerlo todo en uno, este es el primero de los cuantos que hay por ahí. ;)

¿Alguna ayuda para hacerlo?

Descargas:

Editor Hexadecimal

Proyecto Visual C# para facilitar los ejemplos.

ROM funcional de SNES para cargarlo en el proyecto y verlo en el editor hexadecimal.

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Eleкtro

#1
¿Cual es la pregunta en cuestión?, imagino que en Google podrás encontrar las especificaciones del formato SMC aun hoy en día, y sabiendo eso sería suficiente para localizar e identificar toda la información que necesitas.

Si la pregunta es "¿cómo obtener el nombre?":
Código (vbnet) [Seleccionar]
Public Function GetRomName(ByVal filepath As String) As String

   Dim buffer As Byte() = Enumerable.Repeat(New Byte, capacidadDelNombre).ToArray

   Using fs As New FileStream(filepath, FileMode.Open)

       fs.Seek(offset, SeekOrigin.Begin)
       fs.Read(buffer, 0, capacidadDelNombre)
       fs.Close()

   End Using

   Return String.Join("", From b As Byte In buffer Select Convert.ToChar(b)).TrimEnd({" "c})

End Function


Saludos!








Meta

Hola:

Lo he pasado a C#, espero que no importe.
Código (csharp) [Seleccionar]

public string GetRomName(string filepath)
{

byte[] buffer = Enumerable.Repeat(new byte(), capacidadDelNombre).ToArray;

using (FileStream fs = new FileStream(filepath, FileMode.Open)) {

fs.Seek(offset, SeekOrigin.Begin);
fs.Read(buffer, 0, capacidadDelNombre);
fs.Close();

}

return string.Join("", from b in bufferConvert.ToChar(b)).TrimEnd({ ' ' });

}


http://converter.telerik.com/

¿Cómo ese código encuentre el nombre?

Da error en C#.
Código (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.IO; // No olvidar.

namespace SNES_EP
{
    public partial class Form_Principal : Form
    {
        public Form_Principal()
        {
            InitializeComponent();
        }
       
        private void button_Abrir_Click(object sender, EventArgs e)
        {
            Abrir_Archivo();
            Leer_ROM();
        }

       

            public string GetRomName(string filepath)
    {
                int capacidadDelNombre = 15;
                string offset = "101C0";
     
    byte[] buffer = Enumerable.Repeat(new byte(), capacidadDelNombre).ToArray;
     
    using (FileStream fs = new FileStream(filepath, FileMode.Open)) {
     
    fs.Seek(offset, SeekOrigin.Begin);
    fs.Read(buffer, 0, capacidadDelNombre);
    fs.Close();
     
    }
     
    return string.Join("", from b in bufferConvert.ToChar(b)).TrimEnd({ ' ' });
     
    }
        void Leer_ROM()
        {

        }

        void Abrir_Archivo()
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox_Archivo.Text = openFileDialog1.FileName.ToString();
            }
        }

        private void checkBox_Información_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox_Información.Checked == true)
            {
                Width = 643;
                Height = 783;
            }

            else
            {
                Width = 643;
                Height = 508;
            }
        }

        private void abrirArchivoToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }
    }
}


En VB.
Código (vbnet) [Seleccionar]
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
Imports System.Windows.Forms

Imports System.IO
' No olvidar.
Namespace SNES_EP
Public Partial Class Form_Principal
Inherits Form
Public Sub New()
InitializeComponent()
End Sub

Private Sub button_Abrir_Click(sender As Object, e As EventArgs)
Abrir_Archivo()
Leer_ROM()
End Sub


Private Sub Leer_ROM()

End Sub

Private Sub Abrir_Archivo()
If openFileDialog1.ShowDialog() = DialogResult.OK Then
textBox_Archivo.Text = openFileDialog1.FileName.ToString()
End If
End Sub

Private Sub checkBox_Información_CheckedChanged(sender As Object, e As EventArgs)
If checkBox_Información.Checked = True Then
Width = 643
Height = 783
Else

Width = 643
Height = 508
End If
End Sub

Private Sub abrirArchivoToolStripMenuItem_Click(sender As Object, e As EventArgs)

End Sub
End Class
End Namespace


Vamos haber si esto sale.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Eleкtro

#3
Cita de: Meta en  5 Junio 2015, 12:51 PMDa error

Si un código te da error, al menos especifica que error, el mensaje de error, y donde se produce, se te ha dicho ya en varias ocasiones en otros posts.

Dicho esto, el error que tienes es obvio, los valores hexadecimales en .Net no se manejan cómo strings, el datatype que espera el parámetro "offset" del método "FileStream.Seek()" es un entero (Int64/Long), por ende, debes usar un valor de ese tipo.

De todas formas te comento que la manera de utilizar valores hexadecimales es escribiendo enteros literales (menos aquellos métodos que acepten un formato de String hexadecimal).

En VB.Net:
Dim value as Integer = &H101C0

En C#:
int value = 0x101c0;

FileStream.Seek Method - MSDN
Convert.ToInt64(String, Int32) Method - MSDN

Hexadecimal literals (C#) - MSDN
Hexadecimal literals (Visual Basic) - MSDN

Saludos








Meta

Hola:

Gracias por la información. Me he olvidado de comentar los errores. Sorry.

He encontrado un código hecho en C#, lo que veo que es muy viejo, ya que la programación tiene cosas diferente, algunos detalles básicos. Te dejo el archivo original.
Código (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace SnesKit
{
    public enum BankTypeEnum { Lo, Hi };
    public class RomDump
    {
        // Indica si la ROM tiene el smc header o no
        bool SmcHeader;

        // Indica la localización del header de SNES
        int HeaderLocation;

        // Array con los datos de la ROM
        public byte[] Data;

        // Los diferentes datos que obtenemos de la ROM
        public string Name;
        public byte Layout;
        public byte CartridgeType;
        public byte RomSize;
        public byte RamSize;
        public byte CountryCode;
        public byte LicenseCode;
        public byte VersionNumber;
        ushort Checksum;
        ushort ChecksumCompliment;
        public BankTypeEnum BankType;

        // Esta funcion permite el analisis de ROMS de SNES con extensiones SMC y SFC
        public RomDump(byte[] rom)
        {
            this.Data = rom;
            // Comprobamos si existe el header smc
            if (this.Data.Length % 1024 == 512)
                SmcHeader = true;
            else if (this.Data.Length % 1024 == 0)
                SmcHeader = false;
            else
                throw new Exception("Archivo de rom invalida.");
            this.HeaderLocation = 0x81C0;

            if (HeaderIsAt(0x07FC0)) // La Rom es LoROM
            {
                this.BankType = BankTypeEnum.Lo;
            }
            else if (HeaderIsAt(0x0FFC0))
            {
                this.BankType = BankTypeEnum.Hi;
            }

            // Leemos el Header
            ReadHeader();

        }
        // Función para comprobar si el header esta en la dirección correcta
        private bool HeaderIsAt(ushort addr)
        {
            this.HeaderLocation = addr;
            return VerifyChecksum();
        }

        // Offset 0x07FC0 in a headerless LoROM image (LoROM rom sin smc header)
        // Offset 0x0FFC0 in a headerless HiROM image (HiROM rom sin smc header)
        // verifica el checksum
        private bool VerifyChecksum()
        {
            // La rom tiene header smc
            if (SmcHeader)
                this.HeaderLocation += 512;

            this.ChecksumCompliment = BitConverter.ToUInt16(this.Get(0x1C, 0x1D), 0);
            this.Checksum = BitConverter.ToUInt16(this.Get(0x1E, 0x1F), 0);
            ushort ver = (ushort)(this.Checksum ^ this.ChecksumCompliment);
            return (ver == 0xFFFF);
        }

        private void ReadHeader()
        {
            this.Name = Encoding.ASCII.GetString(this.Get(0x00, 0x14)); // 21 chars
            this.Layout = this.At(0x15);
            this.CartridgeType = this.At(0x16);
            this.RomSize = this.At(0x17);
            this.RamSize = this.At(0x18);
            this.CountryCode = this.At(0x19);
            this.LicenseCode = this.At(0x1A);
            this.VersionNumber = this.At(0x1B);
        }

        private string GetROmB()
        {
            return String.Format("{0}", this.RomSize);
        }
        private byte[] Get(int from, int to)
        {
            return this.Data.Skip(this.HeaderLocation + from).Take(to - from + 1).ToArray();
        }
        private byte At(int addr)
        {
            return this.Data[this.HeaderLocation + addr];
        }
    }
}


En Visual Basic convertido.
Código (vbnet) [Seleccionar]
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Imports System.IO

Namespace SnesKit
Public Enum BankTypeEnum
Lo
Hi
End Enum
Public Class RomDump
' Indica si la ROM tiene el smc header o no
Private SmcHeader As Boolean

' Indica la localización del header de SNES
Private HeaderLocation As Integer

' Array con los datos de la ROM
Public Data As Byte()

' Los diferentes datos que obtenemos de la ROM
Public Name As String
Public Layout As Byte
Public CartridgeType As Byte
Public RomSize As Byte
Public RamSize As Byte
Public CountryCode As Byte
Public LicenseCode As Byte
Public VersionNumber As Byte
Private Checksum As UShort
Private ChecksumCompliment As UShort
Public BankType As BankTypeEnum

' Esta funcion permite el analisis de ROMS de SNES con extensiones SMC y SFC
Public Sub New(rom As Byte())
Me.Data = rom
' Comprobamos si existe el header smc
If Me.Data.Length Mod 1024 = 512 Then
SmcHeader = True
ElseIf Me.Data.Length Mod 1024 = 0 Then
SmcHeader = False
Else
Throw New Exception("Archivo de rom invalida.")
End If
Me.HeaderLocation = &H81c0

If HeaderIsAt(&H7fc0) Then
' La Rom es LoROM
Me.BankType = BankTypeEnum.Lo
ElseIf HeaderIsAt(&Hffc0) Then
Me.BankType = BankTypeEnum.Hi
End If

' Leemos el Header

ReadHeader()
End Sub
' Función para comprobar si el header esta en la dirección correcta
Private Function HeaderIsAt(addr As UShort) As Boolean
Me.HeaderLocation = addr
Return VerifyChecksum()
End Function

' Offset 0x07FC0 in a headerless LoROM image (LoROM rom sin smc header)
' Offset 0x0FFC0 in a headerless HiROM image (HiROM rom sin smc header)
' verifica el checksum
Private Function VerifyChecksum() As Boolean
' La rom tiene header smc
If SmcHeader Then
Me.HeaderLocation += 512
End If

Me.ChecksumCompliment = BitConverter.ToUInt16(Me.[Get](&H1c, &H1d), 0)
Me.Checksum = BitConverter.ToUInt16(Me.[Get](&H1e, &H1f), 0)
Dim ver As UShort = CUShort(Me.Checksum Xor Me.ChecksumCompliment)
Return (ver = &Hffff)
End Function

Private Sub ReadHeader()
Me.Name = Encoding.ASCII.GetString(Me.[Get](&H0, &H14))
' 21 chars
Me.Layout = Me.At(&H15)
Me.CartridgeType = Me.At(&H16)
Me.RomSize = Me.At(&H17)
Me.RamSize = Me.At(&H18)
Me.CountryCode = Me.At(&H19)
Me.LicenseCode = Me.At(&H1a)
Me.VersionNumber = Me.At(&H1b)
End Sub

Private Function GetROmB() As String
Return [String].Format("{0}", Me.RomSize)
End Function
Private Function [Get](from As Integer, [to] As Integer) As Byte()
Return Me.Data.Skip(Me.HeaderLocation + from).Take([to] - from + 1).ToArray()
End Function
Private Function At(addr As Integer) As Byte
Return Me.Data(Me.HeaderLocation + addr)
End Function
End Class
End Namespace


Creo un proyecto nuevo que se llama igual SnesKit.
Código (csharp,9) [Seleccionar]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SnesKit
{
    class Program
    {
        static void Main(string[] args)
        {

        }
    }
}


Indicado arriba, justo donde pone class Program lo llamaré como el archivo original public class RomDump como indica abajo. No se si esto es obligatorio. Ver código justo abajo.
Código (csharp,9) [Seleccionar]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SnesKit
{
    public class RomDump
    {
        static void Main(string[] args)
        {

        }
    }
}


El código original no veo que use este código que se crea indicado abajo.
Código (csharp,11,12,13,14) [Seleccionar]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SnesKit
{
    public class RomDump
    {
        static void Main(string[] args)
        {

        }
    }
}


He intentado incrustar el código para que me funcione y no me sale.

¿Hay alguna posibilidad?

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

43H4FH44H45H4CH49H56H45H

Lo primero es que debes empezar a estudiar desde el comienzo lo que es .NET, generalidades de namespace, clases, métodos, diferencias entre proyectos con Windows Forms y de consola, etc.

Pero si no quieres aprender nada de eso y solo quieres copiar y pegar, te basta con crear una clase en un proyecto de Windows Forms con ese código y utilizarla desde el formulario principal.

-R IP
:0100
-A 100 
2826:0100 MOV AH,09
2826:0102 MOV DX,109
2826:0105 INT 21
2826:0105 MOV AH,08
2826:0105 INT 21
2826:0107 INT 20
2826:0109 DB 'MI NICK ES CODELIVE.$' 
2826:0127 
-R BX
:0000
-R CX
:20
-N CODELIVE.COM
-W

Meta

#6
Hola:

Verdad. Ahora quiero probar esto cuanto antes. ;)

Empecé otra vez.
Creé una nueva referencia.


Añadí el código dentro.
Código (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace SnesKit
{
    public enum BankTypeEnum { Lo, Hi };
    public class RomDump
    {
        // Indica si la ROM tiene el smc header o no
        bool SmcHeader;

        // Indica la localización del header de SNES
        int HeaderLocation;

        // Array con los datos de la ROM
        public byte[] Data;

        // Los diferentes datos que obtenemos de la ROM
        public string Name;
        public byte Layout;
        public byte CartridgeType;
        public byte RomSize;
        public byte RamSize;
        public byte CountryCode;
        public byte LicenseCode;
        public byte VersionNumber;
        ushort Checksum;
        ushort ChecksumCompliment;
        public BankTypeEnum BankType;

        // Esta funcion permite el analisis de ROMS de SNES con extensiones SMC y SFC
        public RomDump(byte[] rom)
        {
            this.Data = rom;
            // Comprobamos si existe el header smc
            if (this.Data.Length % 1024 == 512)
                SmcHeader = true;
            else if (this.Data.Length % 1024 == 0)
                SmcHeader = false;
            else
                throw new Exception("Archivo de rom invalida.");
            this.HeaderLocation = 0x81C0;

            if (HeaderIsAt(0x07FC0)) // La Rom es LoROM
            {
                this.BankType = BankTypeEnum.Lo;
            }
            else if (HeaderIsAt(0x0FFC0))
            {
                this.BankType = BankTypeEnum.Hi;
            }

            // Leemos el Header
            ReadHeader();

        }
        // Función para comprobar si el header esta en la dirección correcta
        private bool HeaderIsAt(ushort addr)
        {
            this.HeaderLocation = addr;
            return VerifyChecksum();
        }

        // Offset 0x07FC0 in a headerless LoROM image (LoROM rom sin smc header)
        // Offset 0x0FFC0 in a headerless HiROM image (HiROM rom sin smc header)
        // verifica el checksum
        private bool VerifyChecksum()
        {
            // La rom tiene header smc
            if (SmcHeader)
                this.HeaderLocation += 512;

            this.ChecksumCompliment = BitConverter.ToUInt16(this.Get(0x1C, 0x1D), 0);
            this.Checksum = BitConverter.ToUInt16(this.Get(0x1E, 0x1F), 0);
            ushort ver = (ushort)(this.Checksum ^ this.ChecksumCompliment);
            return (ver == 0xFFFF);
        }

        private void ReadHeader()
        {
            this.Name = Encoding.ASCII.GetString(this.Get(0x00, 0x14)); // 21 chars
            this.Layout = this.At(0x15);
            this.CartridgeType = this.At(0x16);
            this.RomSize = this.At(0x17);
            this.RamSize = this.At(0x18);
            this.CountryCode = this.At(0x19);
            this.LicenseCode = this.At(0x1A);
            this.VersionNumber = this.At(0x1B);
        }

        private string GetROmB()
        {
            return String.Format("{0}", this.RomSize);
        }
        private byte[] Get(int from, int to)
        {
            return this.Data.Skip(this.HeaderLocation + from).Take(to - from + 1).ToArray();
        }
        private byte At(int addr)
        {
            return this.Data[this.HeaderLocation + addr];
        }
    }
}


Ahora a investigar com lo llamo y lo ejecute.

https://msdn.microsoft.com/es-es/library/z2kcy19k.aspx?f=255&MSPPError=-2147217396
https://msdn.microsoft.com/es-es/library/ee461504.aspx
https://www.youtube.com/watch?v=Mu2LYOhEMpM

Si que tengo que leer. ;)

Gracias por todo.



Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/