Ps2Dis Extending a String / Relocating a String in .hack//Fragment

Programs and files needed:

PS2dis
Any Hex editor. In this example I am using HxD though.
HACK_00.ELF (This is found on your .hack.//Fragment disk.) (This is also the online ELF for the game, the single player version is HACK_01.ELF

Optional

Socom 2 Imposter Maker by Dark Killer ( I used this to convert text to hexadecimal. It’s not needed but it makes it quicker.)

Problem

When translating this game from Japanese to English you tend to run into space constraints when dealing with how many letters you can cram in a memory location.  The problem came up where a translation wasn’t correct and since there just wasn’t room to actually have the correct text it instead was made to be something else. As a quick example the Twinblade spell “Tiger Claws” is currently just “Claws”.

A way to fix this issue

In the game .hack//fragment strings are loaded in by pointers.
For this example I am going to show how we can extend a string past the limit it currently has.
Currently I have a level 15 Blademaster that knows the spell Vak Slash and I want to call it something else, something longer.

So we open up PS2Dis and take the HACK_00.ELF and drag it over to PS2Dis. Press Control G and type the following “Vak Slash”, you should see something like this:
ps2Dis Label List

Double click on “Vak Slash” and you will be brought to the place in the file where it exists.
ps21Dis ValSlash Label

As you can see, there isn’t much room after the “h” to really add anything more to this string. So what we need to do now is find the pointer that checks this address “0060a940” and loads this string.

Press Control F and type in the following: 40a96000. Check as hex string as shown below:
ps2Dis Find Hex String

Click ok and you will be brought to the address “004cac80”. This is the pointer. If you press W while on this line and then enter twice you will see that it shows “Vak Slash”. Take note of the data of this address since we will need this later when we go to hex edit our changes in. The pattern is 40a96000.
ps2Dis Vak Slash Pointer

Take note of the pointer address “004cac80” because we will need to come back here later.

So now we need to find an area in this file that is empty. The best way to do this is to Press Control F again and enter a bunch of zeros. So something like 000000000000000000000000000000000000000000000000000000000000000000000000 should be just fine. Once you press enter you should end up at the address “004cfca0”. If you look a few addresses below it you will see that there is a decent amount of space to work with so this is where we will be adding in our new text.
ps2Dis Empty Memory

Take note however of the data in address “004cfc9c” because this will be important when it comes to hex editing this file later. I will give you the hex pattern here so you won’t have to worry about it later. The pattern is b0437000.

Creating our Text

To create our new string I am going to use the program S2 Imposter maker that I mentioned above. Once you open the program you will be presented with this:
socom2 Imposter Maker Main Screen

You can ignore everything on here in terms of options. The only thing we care about is the Text box. The address in the second textbox can also be ignored since thats for a different game, all we care about is the data that this generates. So I want to name my spell to Smashy McSmash. I do understand that this string really isn’t that long and probably could fit into the original area in the file but for the sake of keeping this rather simple this will do just fine. I type it into the textbox and the second textbox will update in real time. So you should see something like:
socom2 Imposter Maker Filled In Text

All we care about is the data however what we do not need is the data 20202020. Again this is part of the code that this was originally generating and does not apply to what we are doing. So you can skip the first line and move onto the second.

In PS2Dis copy and paste the data from S2 Imposter Maker in the the lines starting at address “004cfca4”. You should end up with something like this:
ps2Dis Updated Text

You will know if you did this right because in the grey text area in PS2Dis you will see your text:
ps2Dis Grey Window

While this next step is not super important, it could help when it comes to understanding the change we are about to make. So the addresses you just changed, if you press B on every line you will end up turning them in “byte”. Once you do that go back to “004cfca4” and press enter twice. This will create a label. See below:
ps2Dis Byte View

Now that this is done we need to go back to our pointer and have it point to the address “004cfca4”. The pointer should now look like this:
ps2Dis Vak Slash Pointer Update

 

You will notice that it still says “Vak Slash”. However on the far right it will actually show what it’s pointing to. The reason it say’s “Vak Slash” Still is because when we hit enter on it twice it just created a label. You can remove it by hitting enter on it and deleting the text in the label but it’s really not that important. So as far as this is concerned we are done with our setup and we can now start writing this data to the file. Do not close PS2Dis since we will be needing this still to know what data to add into the HACK_00.ELF file.

Modifying the ELF File

Open HxD and drag the HACK_00.ELF into it. The first thing you may notice is that the addresses on PS2Dis and HxD don’t quite match up. That’s fine, its not important.

Now we want to write our changes and the first place to start is with the pointer. In HxD press Control F and enter the the hex pattern 40a96000 and select Hex-Values for DataType.
You will be taken to the place in the file where this exists and this would be our pointer. We need to change the 4 bytes to our new address. In PS2Dis on the make sure the pointer line is highlighted and in the grey textbox take the 4 bytes A4 FC 4C 00 and replace 40 A9 60 00 in HxD. When you make a change it will be marked in red in HxD.
hxd Opened Elf

Now we want to edit in our new text into HACK_00.ELF.  In PS2dis make sure your pointer address is selected and press spacebar. The line will now change from the dark blue to a grey. Press the right arrow key on your keyboard and it will take you to your new text that you entered in prior. Now since this area in the original file is nothing but zeros doing a Hex Value search for this would be a pain.

This is why I said to take note of the data in address “004cfc9c” since we are going to use that as what we search for in HxD. In HxD press Control F and enter the hex pattern b0437000 and press ok. You will be brought to a new location in the file. Now need to skip the next 4 bytes since in pcsx2 we did that as well. Just as we did with the pointer we are going to enter our text. In PS2dis go to the first line in your new text and in the grey text above take that and just enter it into HxD. You should end up with this:
hxd Updated Code

Once this is done you can save you changes in HxD. Now if you make an ISO of your game and copy the edited HACK_00.ELF you made and launch the game (granted you have the same spell) you will see your change in game.

MSSQL Sub Query

This is written using Microsoft SQL Server however a lot of this can carry over just fine to other SQL variants with little change. I am also using SQL Management Studio 2016 when writing this query. This can be found here.

Sub queries come handy when you need to return data from multiple tables but need that data Summed up or some form of calculation done on them. This isn’t the only scenario where these are useful but in this example that’s what I will be doing.

The example below does not require you to create any tables as everything is done in memory.

Creating our tables:

DECLARE @Users TABLE (
	UserID INT IDENTITY(1,1) PRIMARY KEY, 
	FirstName VARCHAR(25), 
	LastName VARCHAR(25)
 
); 
 
DECLARE @items TABLE (
	ItemID INT IDENTITY(1,1) PRIMARY KEY, 
	ItemName VARCHAR(150), 
	PricePerUnit NUMERIC(5,2)
 
); 
 
DECLARE @sales TABLE (
	SaleID INT IDENTITY(1,1) PRIMARY KEY,
	UserID INT, 
	ItemID INT, 
	AmountSold INT
 
);

 

The “@” tells SQL Server that we are creating a variable and in this case the data type for that variable is a table.

Notes:
IDENTITY(1,1) means that this field auto increments. This is great for Primary keys so you do not have to know what the last ID was, it will do that for you and insert it.

Now we want to insert data into these table so we have something to lookup later on.

Insert statements:

INSERT INTO @Users VALUES('Bill','Dozer');
INSERT INTO @Users VALUES('Bob','Smith');
 
INSERT INTO @items VALUES('Running Boards',52.79);
INSERT INTO @items VALUES('Pin Strip Decal',22.95);
INSERT INTO @items VALUES('Red paint that makes the car faster',133.70);
 
INSERT INTO @sales VALUES(1,1,30);
INSERT INTO @sales VALUES(1,2,25);
INSERT INTO @sales VALUES(1,3,45);
INSERT INTO @sales VALUES(2,1,92);
INSERT INTO @sales VALUES(2,2,100);
INSERT INTO @sales VALUES(2,3,3);

 

 

Nothing much to say here other than to make sure your data follows the constraints you set when you created the fields in the tables.
If you wish to see the data that was put in you can use these SELECT statements:

SELECT * FROM @Users
SELECT * FROM @Items
SELECT * FROM @sales

 

You will see this:

MS SQL Query Example

 

 

 

 

 

 

 

 

 

Now I want to know how many items each User sold and how much money they made each for those sales as totals.

So this is the data we want. We want the user’s name as well as the Total Stock sold (this would be a sum of the items they sold) and a total dollar amount that was sold per person.

So our resulting table should resemble something like this:

UserName,Total Stock Sold, Sales Total

Now that we know what we want we now need to build a query that gets us this information.

First off we need the user name:

SELECT 
	LastName + ', ' + FirstName AS 'Name'
FROM @Users AS usr

 

The above gives us every user in the Users table and displays their name like Smith, Bob.
We also gave the @Users table an Alias of usr. This becomes important in future steps since we will need to reference this again in our sub queries.

Now we want to get the Total Stock Sold per user. So we are going to add the following to the query we already started:

(
		SELECT
			SUM(AmountSold)
		FROM 
			@Sales AS Sa
		WHERE 
			Sa.UserID = usr.UserID
	) AS 'Total Stock Sold'

 

Sub queries are always encased in parentheses. So this query uses the SUM function on AmountSold From the @Sales table. We also give this table an Alias. SUM will take every row in that column (AmountSold) and add them all together. However since we want to only sum the AmountSold and have it displayed for the correct user we have to tell it to only sum it up for the current User we are on. So we add in a WHERE clause and tell it to do it on records that match. So in this case we want it to only SUM where Sa(@Sales table) UserID matches our usr(Users table) UserID. This is why I said the Alias prior was important since we have to use it to do the matching.

Now that this is done we want to now get the Sales Total. We will now add the following to there query we have been working on:

(
		SELECT 
			SUM(PricePerUnit * Sa.AmountSold)
		FROM 
			@items AS It
		JOIN 
			@sales Sa  ON Sa.ItemID = It.ItemID
		WHERE
			usr.UserID = Sa.UserID
	) AS 'Sales Total'

This query works much like the other however now we are doing some multiplication in the SUM function. We multiply those 2 fields together and them sum all those results together to get the total Sales for that user.

The key difference in this one is that we are also now a JOIN. JOINs are important when you are trying to select from more than one table. In this case we want to match records from the @Sales table and the @Items table. The reason we do this is because we need the PricePerUnit in order to do our calculations.

So now that this is all done the final statement will look like this:

SELECT 
	LastName + ', ' + FirstName AS 'Name',
	(
		SELECT
			SUM(AmountSold)
		FROM 
			@Sales AS Sa
		WHERE 
			Sa.UserID = usr.UserID
	) AS 'Total Stock Sold',
	(
		SELECT 
			SUM(PricePerUnit * Sa.AmountSold)
		FROM 
			@items AS It
		JOIN 
			@sales Sa  ON Sa.ItemID = It.ItemID
		WHERE
			usr.UserID = Sa.UserID
	) AS 'Sales Total'
FROM @Users AS usr

MS SQL Query Result

Wallpaper-Changer (source code)

This version of the wallpaper changer is based on my original code that was written in VB.NET. I chose to re-write this program mainly because the original code was horrible and I’ve been wanting to move a lot of my older programs over to C#.

The main purpose for this program was to be used in windows XP since this wasn’t a feature that it had. It never really worked in a way that I wanted it to (originally) so this re-write corrects a lot of the issues that the original had. I decided to post it on github with the hopes that someone may find it useful in some way.

The code as is isn’t complete. There are some changes I plan on making (currently it just does jpgs) but as the code is , it works.

The code can be found below:

Wallpaper-Changer Github

C# Allow only 1 instance of a form to be opened

This was a problem I ran into with using MDI parents /children forms. You could open the same form over and over and it soon became a mess. The code below will check to see if it already exists and if it doesn’t assign the new form as a child to the mdi parent form and open it.

 

//Code that handles Child forms. May be adding more code to this down the road for customization.
        //No need to write the same code for every form
        private void CreateMDIChild(Form childForm)
        {
            //Checks if child form already exists. Only open if it does not exist in the collection
            FormCollection allForms = Application.OpenForms;
            bool formOpened = false; //Assume that this form does not already exist
 
            foreach (Form frm in allForms)
            {
                if (frm.Name == childForm.Name)
                {
                    //Tried to open form here however it throws an error about the collection being modified. So we create a bool and if the form exists
                    //set it to true
                    formOpened = true;
                }
            }
            //As long as formOpened is false we can open the new form as a child form to the parent
            if (formOpened == false)
            {
                childForm.MdiParent = this;
                childForm.Show();
            }
        }

Using the method

private void loginRegisterToolStripMenuItem_Click(object sender, EventArgs e)
        {    
            CreateMDIChild(new frm_LoginRegister());
        }

Reflector Preventer

reflectorPreventer

This program makes it harder for someone to decompile your program with reflector.
How to use:
Select your .net compiled program and click patch.
To make it so you are able to open the binary with reflector simply select the file and click “Restore File”

This program may throw false positives with some anti virus software.

 

Download

[ASP.NET /VB.NET] Populate a Datagrid view without a database

I wanted to list out some data for a page that wasn’t being pulled from a database but I didn’t want to write out the table and all that. So I dropped a datagridview on to the webpage and wrote some code in the code behind.

ASP.NET Side of things

<asp:GridView ID="grd_Specs" CssClass="footable" runat="server" AutoGenerateColumns="False">
	<Columns>      
		<asp:BoundField DataField="item1" HeaderText="Pc Specs"   />
		<asp:BoundField DataField="itemstat" HeaderText="" />
	</Columns>
</asp:GridView>

 

 

VB.Net Code

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        PopulatePCGrid()
 
    End Sub
 
    Dim DT As New DataTable
    Dim DR As DataRow
 
    Private Sub PopulatePCGrid()
        Dim DS As New DataSet
 
        DT = New DataTable("items")
        DT.Columns.Add("item1")
        DT.Columns.Add("itemstat")
        DR = DT.NewRow
 
        AddRowToGrid("Operating System", My.Computer.Info.OSFullName.ToString)
        DR = DT.NewRow
        AddRowToGrid("Total Memory", ((My.Computer.Info.TotalPhysicalMemory / 1024) / 1024).ToString("N0") & " MB")
 
       grd_Specs.DataSource = DT
 
       grd_Specs.DataBind()
    End Sub
 
    Private Sub AddRowToGrid(ByVal description As String, ByVal data As Object)
        With DR
            .Item("item1") = description
            .Item("itemstat") = data
        End With
        DT.Rows.Add(DR)
    End Sub

 

I will explain this as best as I can.
We create two variables, 1 for the Data Table and 1 for the Data Row.
When we get into PopulatePCGrid we create a new data set and set up the data table to match the gridview layout. If these fields do not match you will get an error on page load. So make sure the fields you want exist in both the gridview and in the code behind.

I wrote a sub proceedure to add rows to the dataTable. This isn’t required but it’s best to break out code that you will be using over and over again and make them into functions /subs.

So we call the proceedure and pass in description and data. Data is an object simply because it could be anything. I didn’t want to limit it to a string or integer because that wouldn’t be true (and in fact on the actual page I wrote this for it wasn’t true).

We then add that row to the data table and go back to PopulatePCGrid to finish the rest of the code. We create a new Datarow and then continue to add more information to the Data table. After we finish that we bind the datagridview and we end up with something like this:

datagridviewExample

 

[VB.NET] MySQL Function to Insert/update/delete with parameters

I wrote this bit of code in a project that I am working on for taking screenshots and uploading them to a remote server.

Basically what this does is it accepts the following parameters:
SQLQuery as a string
Parameters and Values as a string array

I am sure there are probably better ways of doing this however this got the job done in a very little amount of code.

In order to use this you would need to include the MySql dll into your project and then refer to it.

Imports MySql.Data.MySqlClient
Dim connString As String = "server=server.com;database=db_Name;port=3306;user=db_user;password=db_password"
Public Sub SaveUpdateDelete(ByVal sql As String, ByVal parameters() As String, ByVal Values() As String)
	Dim con As MySqlConnection = New MySqlConnection(connString)
 
        con.Open()
        Dim cmd As MySqlCommand = New MySqlCommand(sql, con)
 
        For i = 0 To parameters.Count - 1
            cmd.Parameters.AddWithValue("@" & parameters(i).ToString, Values(i))
        Next
        cmd.CommandText = sql
        cmd.ExecuteNonQuery()
 
        con.Close()
End Sub

 

To make use of this function:

Private sub DoDBStuff
	Dim sql As String = "INSERT INTO db_table(userID,imageHash,notes,lastEditedDate) VALUES(@userID,@imageHash,@imageDescription,NOW())"
	Dim params() As String = {"userID", "imageHash", "imageDescription"}
	Dim Values() As String = {DataBase_UserID, DataBase_UserName & "/" & foldername & "/" & HashedFileName & "." & FileNameParts(FileNameParts.Count - 1).ToString, ""}
 
	SaveUpdateDelete(sql, params, Values)
End Sub

[VB.NET] Reading and Writing to the Registry

This is a piece from my Final fantasy 11 Configurator that I made back when I used to play the game.

  1. Imports Microsoft.Win32

We’ll now make a registrykey variable.

  1. Dim FF_key As RegistryKey

Now we will make sure the location want it stored in that variable.

  1. FF_key = Registry.LocalMachine.OpenSubKey("\Software\Microsoft\", True)

Now to read in the Keys that are already saved by the game. In this part I called a few keys that I wanted information from, so in order to do that I first declare my variables:

  1. Dim key_windowed_mode As String
  2. Dim key_res_1 As String
  3. Dim key_res_2 As String
  4. Dim key_3D_res_1 As String
  5. Dim key_3D_res_2 As String
  6. Dim key_texture_compress As String
  7. Dim key_on_screen_map As String
  8. key_res_1 = FF_key.GetValue("0001")
  9. key_res_2 = FF_key.GetValue("0002")
  10. key_3D_res_1 = FF_key.GetValue("0003")
  11. key_3D_res_2 = FF_key.GetValue("0004")
  12. key_texture_compress = FF_key.GetValue("0018")
  13. key_on_screen_map = FF_key.GetValue("0019")

The (“numbers”) is the key name which holds the information that I wanted.
Now when it comes to writing it’s just as easy:

  1. FF_key.SetValue("0034", 1, RegistryValueKind.DWord

Valuekind.dword is just the datatype, you don’t always needs to do this but for this to work for me in this case I had to.

[VB.NET][C#] Multi-thread / Crossthreading Example

Someone was asking how to do multi-threading in the shoutbox and my original example didn’t work because of cross-threads. This basically means I couldn’t set the value of a control within a thread since it’s considered a different process. Well I did manage to get it to work and I figured I’d post the code here. I will also include the source code both both the VB.net and C# versions below.

VB

  1. Imports System.Threading
  2. Public Class Form1
  3.  
  4. Dim Max As Double = 600000
  5. Dim i As Integer = 0
  6. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  7. ProgressBar1.Maximum = Max
  8. Dim threadFill As Thread = New Thread(AddressOf Thread_FillProgressbar)
  9. threadFill.Start()
  10. End Sub
  11.  
  12. Private Sub Thread_FillProgressbar()
  13.  
  14. For i = 0 To Max
  15. AccessControl()
  16. Next
  17. End Sub
  18.  
  19. Private Sub AccessControl()
  20. If Me.InvokeRequired Then
  21. Me.Invoke(New MethodInvoker(AddressOf AccessControl))
  22. Else
  23.  
  24. ProgressBar1.Value = i
  25. ShowInTaskbar = True
  26. End If
  27. End Sub
  28. End Class

C#

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Threading;
  10. namespace CSharp_multithreading
  11. {
  12. public partial class Form1 : Form
  13. {
  14. public Form1()
  15. {
  16. InitializeComponent();
  17. }
  18.  
  19. int Max = 60000;
  20. int i = 0;
  21. private void Form1_Load(object sender, EventArgs e)
  22. {
  23. progressBar1.Maximum = Max;
  24. Thread threadFill = new Thread(Thread_FillProgressBar);
  25. threadFill.Start();
  26. }
  27.  
  28. private void Thread_FillProgressBar()
  29. {
  30. for (i = 0; i <= Max; i++)
  31. {
  32. accessControl();
  33. }
  34. }
  35.  
  36. private void accessControl()
  37. {
  38. if (InvokeRequired)
  39. {
  40.  
  41. Invoke(new MethodInvoker(accessControl));
  42.  
  43. }
  44. else
  45. {
  46. progressBar1.Value = i;
  47. ShowInTaskbar = true;
  48.  
  49. }
  50.  
  51. }
  52. }
  53. }

VB.NET Source

C# Source