Hi,
I'm working on some tools for a new game called Terra Tech(check it out ^_^).
You can create "techs", save, swap and tweet them. The save file is a png snapshot image. They put the object specifications in the image using steganography. I am trying to reverse engineer this.
Here is an image on my twitter:
https://pbs.twimg.com/media/CRJO2kqWgAEy0hn.png[
^]
or just look on my tweets (new account):
https://twitter.com/GreysonTyrus[
^]
They use the UnityEngines Texture2D to manipulate the image and I don't want to have to build my solution in Unity. I need to recreate the behaviour
They use the png rgba values. The first char should be 'G', the next chunks will be a compressed JSON string using IonicGZip.
I know that Texture2D read the image left to right, bottom to top. I am using Hjg.Pngcs to parse the image.
I had this working at one point, but now it appears that all of the images alpha is 255 (never 254 which i would expect about 50% of the time)
Can anyone parse this image, take the last bit of each pixels rgba values, put them into a byte array and get the first byte to be 'G'(h:x047 / d: 71)?
I have a lot of code but am happy to post whatever you ask for.
Thanks ^_^
Andy
UPDATE: Quote from James: Terra tech Dev (available to contact on forums) to me:
Quote:
Hi!
In short - you're welcome to edit any files you like. You've purchased the game for your own use and we're happy to let you do whatever you want with it (within reason ;) ). BUT - if you encounter any problems with an edited save or a cheated game, we can't support you with fixes as you're playing a version that is no longer connected to ours.
If you wish to share your findings with the community - that is fine too. We only ask that you make it clear that if they tinker with the game and it breaks - we won't be supporting them with fixes.
Thanks for letting us know Andy! x
UPDATE: My Code:
UnitTest: used in place of a "Main" for debugging:
[TestClass]
public class PngFileToolsTests
{
[TestMethod]
public void GetEncodedObjectFromImage()
{
var location = Assembly.GetExecutingAssembly().Location;
location = @"C:\Program Files (x86)\Steam\SteamApps\common\TerraTech Beta\Cabbie.png";
FileInfo info = new FileInfo(location);
PngFileTools tool = new PngFileTools();
var result = tool.GetCodedBytes(info);
Assert.IsNotNull(result);
}
}
The Unity code uses Unities Texture2D to load the image. It is loaded into an array or Color32. This item has an r,g,b, and a byte. They use the last bit to encode the message. I don't have access to Unity Engine tools unless I run my app within Unity. I don't want to to that (why would I). I use
Pngcs[
^] to decode the png files. I have tried reading rows bottom to top, and top to bottom (always left to right) with no joy. My current code just takes the entire byte array of all Least Significant Bits (LSB) of all bytes read at once. Here is the code that does that:
public class PngFileTools
{
private static byte[] PixelArrayBytes(Stream fs)
{
var pngr = new PngReader(fs);
int channels = pngr.ImgInfo.Channels;
if (channels < 4)
throw new Exception("This example works only with RGBA images");
BitArray bits = new BitArray( pngr.ReadRowsInt().Scanlines.SelectMany(r => r.Select(c => c % 2 == 1)).ToArray());
pngr.End();
return bits.ToByteArray();
}
private static int DecodeFromBytes(byte[] carrierPixels, int offset, int numBytes, out byte[] messageBytes)
{
messageBytes = new byte[numBytes];
carrierPixels.Skip(offset).Take(numBytes).ToArray().CopyTo(messageBytes, 0);
return numBytes;
}
public string GetCodedBytes(FileInfo pngFileInfo)
{
byte[] pixelArray;
using (FileStream fs = new FileStream(pngFileInfo.FullName, FileMode.Open))
{
pixelArray = PixelArrayBytes(fs);
}
return CodedBytes(pixelArray);
}
public string GetCodedBytes(Stream pngFileInfo)
{
byte[] pixels = PixelArrayBytes(pngFileInfo);
return CodedBytes(pixels);
}
private static string CodedBytes(byte[] pixels)
{
int num = 0;
byte[] array;
num += DecodeFromBytes(pixels, 0, 1, out array);
char c = (char)array[0];
if (c > 'G' || c < 'A')
{
return null;
}
return "";
}
}
I have used some extension methods, but any that you're missing do just what they say they do. Let me know if you want to look at them and I'll post them