Unpacking FFXi Related Files

One of the many aspects of reversing Final Fantasy XI be it statically on disk or live in memory requires that parts of the game files are unpacked. Square Enix has taken the time to create an internal packer of the games sensitive data for the PE files (.exe and .dll). In many of the game files, there is a packed section called POL1. This section contains the files actual .text section data, but is packed.

For example, this is the games FFXiMain.dll as of Jan 01, 2015:
FFXiMain Sections

In this image you’ll see something strange. The files .text section has a raw size of 0. This is because the actual data does not exist in the file until its unpacked. Instead, the files .text data is actually within the POL1 section. If we load FFXiMain.dll inside of OllyDbg, or any other debugger / disassembler, we will see this at the files current entry point:
FFXiMain Unpacking Routine

Like much of SE’s other packing / encoding methods, the encryption of the section is not very secure or unique.
Some basic shifting and such and the unpacked data is obtained fairly easily.

However, handling this unpacking externally from a static context is a bit more difficult because it involves having to rebuild the PE file on disk after it is unpacked. The .text section must be resized to its proper size containing the new raw data which in turn unaligns all the other sections. So each section must be rebuilt and realigned with the file. Afterward, we must also set the files new size and its new entry point.

Unpacking the file is fairly trivial, we can just steal the decryption method from the games file and use it locally. If we adjust the ASM as needed, we can reuse it like this:

;*******************************************************************************
; XiUnpack.asm (c) 2014 atom0s [atom0s@live.com]
;
; Unpacks a given POL1 section from a file.
; This function is taken from the FFXiMain.dll file.
;*******************************************************************************

.586
.model flat, C
option casemap :none

.code

    ;*******************************************************************************
    ; @brief Unpacks the given POL1 section.
    ;
    ; @param packed         The packed POL1 section to unpack.
    ; @param unpacked       The unpacked buffer to write the data to.
    ;*******************************************************************************
    XiUnpack PROC
        PUSHAD
        MOV EBP, ESP
        MOV ESI, DWORD PTR SS:[EBP + 024h] ; packed section
        MOV EDI, DWORD PTR SS:[EBP + 028h] ; storage
jmp_6:
        MOV ECX, 8
        MOV BL, BYTE PTR DS:[ESI]
        INC ESI
jmp_5:
        SHL BL, 1
        JNB jmp_1
        MOV AL, BYTE PTR DS:[ESI]
        MOV BYTE PTR DS:[EDI], AL
        INC ESI
        INC EDI
        JMP jmp_2
jmp_1:
        XOR EAX, EAX
        MOV AL, BYTE PTR DS:[ESI]
        INC ESI
        MOV EDX, EAX
        MOV AL, BYTE PTR DS:[ESI]
        MOV AH, DL
        AND EAX, 0FFFh
        JE jmp_3
        INC ESI
        NEG EAX
        SHR EDX, 4
        ADD EDX, 3
jmp_4:
        MOV BH, BYTE PTR DS:[EDI + EAX]
        MOV BYTE PTR DS:[EDI], BH
        INC EDI
        DEC EDX
        JNZ jmp_4
jmp_2:
        LOOP jmp_5
        JMP jmp_6
jmp_3:
        POPAD
        RETN
    XiUnpack ENDP
END

This would allow us to call XiUnpack to unpack the POL1 section like this:

XiUnpack((DWORD)ptr_to_packed_data, (DWORD)ptr_to_output_buffer);

So the last bit would be now to load the file locally, dump the PE file information including:

  • DOS Header
  • DOS Stub (If it exists.)
  • Nt Headers
  • Section Entries
  • Section Data

Here is a step by step run down of what we would need to do. I will post the source code to this on Github as well for those interested.

  1. Load the file locally into memory.
  2. Validate the file is a PE file.
  3. Validate the file has a packed POL1 section.
  4. Obtain the POL1 section for its data and raw size.
  5. Obtain the .text section for its virtual size. (This is the size of POL1 unpacked.)
  6. Invoke XiUnpack, as seen above, to unpack the data.
  7. Begin Rebuilding The Unpacked File
    1. Write the original DOS header to the new file.
    2. Write the DOS stub, if it exists, to the new file.
    3. Write the original NT headers to the new file.
    4. Process each section of the file.
      1. If .text section, set the size of raw data to its virtual size.
      2. Set the sections raw data pointer to the previous sections end. (Realigning the sections.)
      3. Realign the sections pointer to raw data and size of raw data to the files section alignment. (Required for Windows to consider the file valid!)
      4. Write the section entry to the file.
      5. Set the file pointer to the sections raw data offset.
      6. Write the sections raw data to the file.
      7. Reset the file pointer to the section table for the next section to be written.
  8. Reset the file pointer to the NT headers offset.
  9. Adjust the files SizeOfImage inside of the NT headers with the new last section information.
  10. Rewrite the NT headers to the file with the new image size.
  11. Close the new file.

At this point our new file should be all set. The result will look something like this:
Unpacked

As you can see here, our .text section is now properly sized (and aligned) to the file. Following the raw data pointer will take us to the unpacked data from POL1 as well. Each following section has had their raw address set to their new locations following the .text’s section data. Setting the raw data pointer is as simple as (rawSize + rawAddress) of the section previous. .text starts at 0x00001000. The next section will start at (.text->RawSize + .text->RawAddress). And so on for each following section.

Something to keep in mind, the POL1 section is not required after being unpacked. We have reset the entry point of the file to its new location. This allows us to completely remove the section if we wanted. Doing so will require us to fix the .rsrc and .reloc sections to properly align in the file with the POL1 section removed. For this example and source base, I just left the section in place. It does not hurt having it there, it just takes up some extra space.

Some side notes on how certain information is handled..

Aligning The Sections
According to MSDN, ‘SizeOfRawData’ and ‘PointerToRawData’ must be section aligned. It is required to be a multiple of the files ‘FileAlignment’ value found within the NT headers optional header. This is simple to do. Because it needs to be a multiple we want to make sure we are rounding up. In order to do, we would do the following:

(((in + align - 1) / align) * align)

So as an example, our .text section in FFXiMain.dll would look like this:

PointerToRawData = (((0x400 + 0x200 - 1) / 0x200) * 0x200); // would equal: 0x400
SizeOfRawData = (((0x2F4C2E + 0x200 - 1) / 0x200) * 0x200); // would equal: 0x2F4E00

Obtaining The Entry Point
With the example code base that is on Github, we will see the following for the entry point:

        auto baseAddressOffset = *(DWORD*)(((DWORD)packed + polSection.Misc.VirtualSize) - 0x51);
        auto baseAddressOriginal = ntHeaders.OptionalHeader.AddressOfEntryPoint;
        ntHeaders.OptionalHeader.AddressOfEntryPoint = (baseAddressOffset + baseAddressOriginal) + 0x9B;

Here we are reading the original code from the packed file. The first read is the jump offset to the last jump going to the actual original entry point. Next, we obtain the original entry point then we calculate the original from the given offset. The + 0x9B is the offset to the last JMP to the entry point. So we are calculating the difference from the original entry point to the real entry point based on the jump.

Github link: https://github.com/atom0s/xiunpack

Simple Memory Scanner Example

Wrote this for someone that was asking for help on Cheat Engine’s forums. This is a very very basic and light-weight memory scanner that will scan for 4 byte values.

/** 
 * Simple Memory Scanner Example 
 * (c) 2014 atom0s [atom0s@live.com] 
 */ 

#include <Windows.h> 
#include <string> 
#include <TlHelp32.h> 

/** 
 * @brief The target process to scan within. 
 */ 
#define TARGET_NAME "winmine.exe" 

/** 
 * @brief Obtains the process id of the given target. 
 * 
 * @return The process id if found, 0 otherwise. 
 */ 
unsigned int getTargetProcessId() 
{ 
    PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; 

    // Obtain a snapshot of the current process list.. 
    auto handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    if (handle == INVALID_HANDLE_VALUE) 
        return 0; 

    // Obtain the first process.. 
    if (!::Process32First(handle, &pe32)) 
    { 
        ::CloseHandle(handle); 
        return 0; 
    } 

    // Loop each process looking for the target.. 
    do 
    { 
        if (!_stricmp(pe32.szExeFile, TARGET_NAME)) 
        { 
            ::CloseHandle(handle); 
            return pe32.th32ProcessID; 
        } 
    } while (::Process32Next(handle, &pe32)); 

    // Cleanup.. 
    ::CloseHandle(handle); 
    return 0; 
} 

/** 
 * @brief Entry point of this application. 
 * 
 * @param argc  The count of arguments passed to this application. 
 * @param argv  The array of arguments passed to this application. 
 * 
 * @return Non-important return. 
 */ 
int __cdecl main(int argc, char* argv[]) 
{ 
    // Obtain the target process id.. 
    auto processId = getTargetProcessId(); 
    if (processId == 0) 
        return 0; 

    // Open a handle to the target.. 
    auto handle = ::OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId); 
    if (handle == INVALID_HANDLE_VALUE) 
        return 0; 

    // Obtain the current system information.. 
    SYSTEM_INFO sysInfo = { 0 }; 
    ::GetSystemInfo(&sysInfo); 

    auto addr_min = (long)sysInfo.lpMinimumApplicationAddress; 
    auto addr_max = (long)sysInfo.lpMaximumApplicationAddress; 

    auto found = 0; 

    // Loop the pages of memory of the application.. 
    while (addr_min < addr_max) 
    { 
        MEMORY_BASIC_INFORMATION mbi = { 0 }; 
        if (!::VirtualQueryEx(handle, (LPCVOID)addr_min, &mbi, sizeof(mbi))) 
        { 
            printf_s("Failed to query memory.\n"); 
            break; 
        } 

        // Determine if we have access to the page.. 
        if (mbi.State == MEM_COMMIT && ((mbi.Protect & PAGE_GUARD) == 0) && ((mbi.Protect & PAGE_NOACCESS) == 0)) 
        { 
            // 
            // Below are flags about the current region of memory. If you want to specifically scan for only 
            // certain things like if the area is writable, executable, etc. you can use these flags to prevent 
            // reading non-desired protection types. 
            // 

            auto isCopyOnWrite = ((mbi.Protect & PAGE_WRITECOPY) != 0 || (mbi.Protect & PAGE_EXECUTE_WRITECOPY) != 0); 
            auto isExecutable = ((mbi.Protect & PAGE_EXECUTE) != 0 || (mbi.Protect & PAGE_EXECUTE_READ) != 0 || (mbi.Protect & PAGE_EXECUTE_READWRITE) != 0 || (mbi.Protect & PAGE_EXECUTE_WRITECOPY) != 0); 
            auto isWritable = ((mbi.Protect & PAGE_READWRITE) != 0 || (mbi.Protect & PAGE_WRITECOPY) != 0 || (mbi.Protect & PAGE_EXECUTE_READWRITE) != 0 || (mbi.Protect & PAGE_EXECUTE_WRITECOPY) != 0); 

            // Dump the region into a memory block.. 
            auto dump = new unsigned char[mbi.RegionSize + 1]; 
            memset(dump, 0x00, mbi.RegionSize + 1); 
            if (!::ReadProcessMemory(handle, mbi.BaseAddress, dump, mbi.RegionSize, NULL)) 
            { 
                printf_s("Failed to read memory of location: %08X\n", mbi.BaseAddress); 
                break; 
            } 

            // Scan for 4 byte value of 1337.. 
            for (auto x = 0; x < mbi.RegionSize - 4; x += 4) 
            { 
                if (*(DWORD*)(dump + x) == 1337) 
                    found++; 
            } 

            // Cleanup the memory dump.. 
            delete[] dump; 
        } 

        // Step the current address by this regions size.. 
        addr_min += mbi.RegionSize; 
    } 

    printf_s("Found %d results!\n", found); 

    // Cleanup.. 
    ::CloseHandle(handle); 
    return ERROR_SUCCESS; 
}

Grim Dawn File Archive / Database Extractors

I’ve recently bought Grim Dawn after wanting an offline ARPG to play while my internet is utter shit or offline. I stumbled across Grim Dawn by accident doing some Google searches looking for something that has a similar Diablo feel to it. GD happens to be by the makers of Titan Quest, which I did enjoy somewhat when I was younger, however I never really got too in depth with playing it. But from the look of the game having that Diablo 2 look and feel, I wanted to give it a try.

Fast forward to now, I’ve been personally interested in the game data files to see how things are stored, what is where, and so on as a local lookup for information about the game, such as where monsters spawn, what they drop, and such. Which lead to the creation of the two following tools.

grimarc – Grim Dawn Archive File Extractor (.arc)
This is a simple tool to extract the .arc archive files for Grim Dawn.
https://github.com/atom0s/grimarc

grimarz – Grim Dawn Database File Extractor (.arz)
This is a simple tool to extract the .arz database files for Grim Dawn.
https://github.com/atom0s/grimarz

At this time, these tools are simply for static analysis locally, they do not offer any ability to edit, read, modify or repackage the files they have since extracted. My interest is simply in seeing the content of the files, not to modify them.

Installing Mono on CentOS 6.x

Since yum does not include a default mono package / repo, installing it has become a fairly annoying task.

Here are some steps to get Mono installed on CentOS 6.x (I am using 6.5 as of this post):

  • Create a new repo entry under /etc/yum.repos.d/ named mono.repo
  • Enter the below into the file with your favorite editor:

[home_tpokorra_mono]
name=mono and monodevelop (CentOS_CentOS-6)
type=rpm-md
baseurl=http://download.opensuse.org/repositories/home:/tpokorra:/mono/CentOS_CentOS-6/
gpgcheck=1
gpgkey=http://download.opensuse.org/repositories/home:/tpokorra:/mono/CentOS_CentOS-6/repodata/repomd.xml.key
enabled=1

  • Next install all of the mono packages needed via: yum install mono*-opt
  • (Optional) In some cases you will need to register the format yourself, use the following to do so:

‘:CLR:M::MZ::/usr/local/bin/mono:’ > /proc/sys/fs/binfmt_misc/register

  • Next to always have mono in the path variable we can add it to .bashrc
    • To do this, open ~/.bashrc in your favorite editor and add the following line to it:

export PATH=/opt/mono/bin:$PATH

  • Lastly you can either restart the machine to make the path take effect, or you can execute the following to do it:

export PATH=/opt/mono/bin:$PATH

  • Done! Mono should now be working 🙂
  • You can use mono –version to output the version information.

Thanks to my friend devnull for piecing together these parts in helping me get Mono working. 🙂

Honeywell Total Connect (Windows Phone) Information / Source Code

Been a while since I posted here. Have had a crazy past year so I have not had time to do much on this blog. But I am back for a topic that I have been getting emailed about a lot since my previous post about the Total Connect tool I made for Windows Phone.

Be aware: The information in this post is for educational purposes only. While the app is free, I do still respect Honeywell and their services. Please do not abuse this information. Use at your own risk. I am not liable for what happens when you use anything posted here or referenced by me.

Obtaining The APK Locally
The link to the APK on the play store can be found here: https://play.google.com/store/apps/details?id=com.alarmnet.tc2
We can see that the file name is ‘com.alarmnet.tc2’, Just add .apk to the name and Google. You will find a dozen sites with the APK. You can also root your phone to gain access etc. but I will not cover that here.

Decompilg The APK
Now that we have the APK we need to decompile it. You can use the following tools to accomplish this:
– dex2jar: https://code.google.com/p/dex2jar/

With this tool, you can easily convert the .dex file inside the .apk file (it is just a .zip file!) back to a usable jar file.
Simply drag and drop the .dex file onto ‘d2j-dex2jar.bat’ and you’re done.

Next to decompile the Jar to readable source code I used:
– Jd-Gui: http://jd-gui.softpedia.com/

Again simply open the .jar now with this tool and you will see the decompiled source.

Understanding The Source
While I do recommend looking through the entire thing to get accustom to their setup, I will point out what is important.
– com\alarmnet\tc2\rcmobile\rcConn.java
– com\alarmnet\tc2\rcmobile\rcSecure.java

Both of these files contain the service call data and connection flow that we will need to follow in our application. I really recommend studying these because their method of handling the connection is fairly convoluted in my opinion.

Making The Connection (Service Call Flow)
Now that we have the source, we can analyze the setup of the service calls and how they are handled. For one, we see the main service object can be found here:
https://rs.alarmnet.com/tc21api/tc2.asmx

They were nice enough to use a Windows service so this makes things a bit easier while working with it at least. 🙂

To make a login request, we have a two step process:
– AuthenticateUserLogin : Which does what it sounds like, it auths our login information.
– GetSessionDetails : Obtains information about our session. (ie. Session Id, Module Flags, Security Locations, User Info)

To even login, we are required to give the service some information:
– Our Application Id
– Our Application Version

Given that the Windows phone does not have an appId/version for this, we use the Android one to fake the call. In the case of the code I wrote, the version info was:
– Application Id: 34857971
– Application Version: 2.2.0

The next step is to keep the session activated and alive. After we login, the app creates a thread to keep pinging the service. Inside that thread, the app was calling KeepAlive and GetPanelMetaDataAndFullStatusByDeviceID.

Thankfully, we are given the nice usage of async callbacks for everything when we reference their service. So we can make a fairly decent setup that can be UI friendly.

Arming Our Security System (And Disarming..)
Next was seeing how we arm and disarm the system. Here I found that the call was made to ArmSecuritySystem. This handled both arming for away and stay modes. This takes a number of params which I am not 100% sure if the user id param was required or not. I would recommend not sending it at all if you do not have to. My examples sent it just to be safe when I was testing this setup.

Following suit, to disarm the system we have a similar call: DisarmSecuritySystem

Status Information And The Like
Finally, with the information obtained status codes and bitmasks were all that was left to obtain the information data. When querying for the panel status in the keep alive, we can get a number of results that mean different things (based on different security systems):

  • 10200 – Disarmed
  • 10211 – Disarmed (bypass)
  • 10201 – Armed Away
  • 10202 – Armed Away (bypass)
  • 10205 – Armed Away (instant)
  • 10206 – Armed Away (instant-bypass)
  • 10203 – Armed Stay
  • 10204 – Armed Stay (bypass)
  • 10209 – Armed Stay (instant)
  • 10210 – Armed Stay (instant-bypass)
  • 10307 – Arming
  • 10308 – Disarming

When we arm or disarm the system, we can get a specific result return of: 4500
When this occurs the system wants us to force-request the current panels last command state. When we do this, that service call can have the following returns:

  • 0 – Success
  • -4502 – Invalid pin. (Yes, that is a negative result.)
  • 4501 – Repoll Required (Command is currently scheduled.)

Also when we call the GetPanelMetaDataAndFullStatusByDeviceID method, we are given the current panels zone data. These zones can have a series of flags in their status mask. The status codes are as follow for the zones:

  • 0 – Normal
  • 1 – Bypassed
  • 2 – Faulted
  • 8 – Trouble
  • 16 – Tampered
  • 32 – Supervision Failed

Putting It All Together

When I first started working on this I made a simple test application which can be seen here:

After getting the test app to work fairly well, I moved to working on the demo phone app I created. Which can be seen here:

Getting it to work simply for myself was great. I was happy to get it in a somewhat working manner. However, I am by no means a Windows Phone developer. This was my first solo app project for the WP7 platform and I can honestly say my last. I am not a fan of Windows Phones at all and I have since gotten rid of mine and moved to Android.

About The Source Code
The source code is in a beta “working” state. Meaning, things are thrown together just to get it to work and test things out kind of state. I did not take the time to fully cleanup the code, it may [read: does] still have errors and problems. I cannot guarantee it will work for everyone and such. The following sources will be of my original test application (proof of concept) and the phone app.

I do wish that people at least honor me by giving me credits if you use this source code. I also do request that you do not sell your app, if you make one, for money. Honeywell offers this service free of charge on all other platforms, there is no reason to nickle and dime people for a simple feature-set like this.

Windows Proof of Concept Client: https://github.com/atom0s/HoneywellWindowsPoC
Windows Phone 7 Proof of Concept App: https://github.com/atom0s/HoneywellWP7PoC

Honeywell Total Connect Windows Phone

After my recent move to my partners house, I learned he has a security system that is manufactured through Honeywell. Within the first week of living at the new house he had set me up with my own security code and login to use the system so I can come and go freely as needed. Sadly, I learned quickly that my phone (Windows Phone, HTC Trophy) does not have any type of app to communicate with the system like iPhone, Android, and Blackberry do.

So I endeavored a bit to see what all the app does on the Android phone by getting my hands on the APK via Google. Doing a little research you can find the app on the Google market here:
https://play.google.com/store/apps/details?id=com.alarmnet.tc2

The URL tells us the name of the app file as well being:
com.alarmnet.tc2

So slap on the extension .apk and Google away to find the actual file.


Getting The Goods

The next step after obtaining the .apk file is getting it back to readable code. To do this I found a toolkit called dex2jar found here:
https://code.google.com/p/dex2jar/

With this, you can easily convert the .dex file inside the .apk (its just a .zip file) back to the usable .jar file.
Simply drag and drop the .dex onto the ‘d2j-dex2jar.bat’ and you’re done.

Next I used jd-gui.exe to decompile the .jar back to usable code, you can find that here:
http://jd-gui.softpedia.com/

With that you can load the .jar and then save all the sources via the File menu. This will produce the .java files that are readable source code again.


Whats Important To Us

Now that I was able to get the source back, I started looking for what would be useful to me. Quickly, I came across:
com\alarmnet\tc2\rcmobile\rcConn.java
com\alarmnet\tc2\rcmobile\rcSecure.java

Both of which have very useful information pertaining to the app. Through tracing functions in these two files I quickly found out that the application was communicating with a WCF service via SOAP calls. The service location is found here:
https://rs.alarmnet.com/tc21api/tc2.asmx


Call Flow — Making It Work

Given that I have the full src to the Android app now, I took time to analyze things to see if there was any small quirks I had to follow, and sure enough there are. To start, logging in is a two-step process:
AuthenticateUserLogin -> GetSessionDetails

The session details include information about the users access to the security system including:

  • Session ID
  • Module Flags
  • Security Locations
  • User Information

The Security Locations include information about each device that the user has access to (panels etc) inside that location. All of which are needed when making various other calls to the security service.

After being logged in, the session id returned has to be kept alive using another call:
KeepAlive

This call keeps the session active on the service end and allows us to keep making various other calls to the service without having to login again. From the look of it, sessions only have to be pinged once every 2 minutes as seen by the keep alive timer code here:

  public void startKeepAliveTimer()
  {
    this.timer = new Timer();
    this.cmdtimer = new CmdTimer();
    this.timer.schedule(this.cmdtimer, 60000L, 120000L);
  }

Next, we have to keep querying the panel for status information, arm status, etc. However I didn’t see a clear-cut method of how the Android app did this. So I instead assumed 10 seconds would be enough between each query. Which can be obtained using the service call:
GetPanelMetaDataAndFullStatusByDeviceID


Phase 1 — Trial and Error

My first night coding, I made a quick test app to see if I could really login to the service. Which I was greeted with the need of two more specific pieces of information. The login call looks like this:

AuthenticateUserLogin(username, password, applicationId, applicationVersion);

Clearly we do not have a real appId and appVersion for the Windows Phone since there is none. So we have to improvise and use what we have. Inside the Android app I found the Android values. The application id was found in a .java file with the line of code being:

KSoapUtils.createElementAndSetEscapedText(localElement3, "ApplicationID", "ipv", Integer.valueOf(34857971));

The application version was a little more tricky since its stored in the AndroidManifest.xml. Which is also encrypted separately. To decompile the xml I found a tool called apktool:
https://code.google.com/p/android-apktool/

To get the info that I needed here, you can use the command:
java -jar apktool.jar decode -s com.alarmnet.tc2.apk

This will decode just the resources which includes the needed AndroidManifest.xml file. Now that its decoded I found the version value near the top which was:
android:versionName=”2.2.0″

So now the login call can be made using:

AuthenticateUserLogin(this.txtUsername.Text, this.txtPassword.Text, 34857971, "2.2.0");

Next up was handling the returns. After some analysis, I figured that all commands return a base object that has a ResultCode and ResultData. From there I figured all returns expect ResultCode to equal 0 to be successful. Otherwise it was an error and then ResultData would be filled with the error string. This made coding the handlers a bit easy.

My resulting test project looked like this:

The project was simple and only included a few features which were:

  • Login To Service
  • Obtain Session Info
  • Query Panel Status
  • Query Zone Status’ (To see faults, trips, issues, etc.)
  • Disarm, Arm (Away), and Arm (Stay) the system.

The disarming and arming of the system both use the users 4-digit pin-code to properly work as well.


Phase 2 — Phone Version

Today started phase 2 which was bringing the v1 beta onto the phone, with a more appealing look. For this I used the assets and resources from the Android version of the application for my phone app. After a few hours of tinkering and such, I found out that the service calls in the Windows Phone turned into async calls which was I not expecting. So I had to land up rewriting my base entirely to work with this. Although I prefer working with async anyway, it was just not expected.

After a bit of work, I made two basic screens that are fully functional so far which are the login and main security panel screens, seen here:

At this time I do not have any other features working or implemented. I do plan to add the usage log and the zone information screens soon, but outside that I do not have a system with cameras and other features to get those working.

I also do not have a AppHub developer account to push this onto the market place either. (It would be free, perhaps with ads or something to make some money for my time.) But at this time it was more of a project for myself.

Feel free to ask questions if you have any. 🙂

Blog Revamp — Starting over..

Hello everyone,

I have once again kind of neglected this blog and stopped posting in it although I have been busy coding on various projects. Bits and pieces of things I could have shared but haven’t seem to cross my mind a lot granted I know I’m no professional or anything when it comes to coding, I still enjoy helping others and sharing what I do know.

My blog was fairly random and unorganized before. I lacked using categories on a lot of posts, things were poorly written and rushed, and so on. Instead I’d rather this be a more professional looking thing than just a dump for misc chunks of code. With that, I am revamping the blog; within reason. I have removed all the old posts and will be reposting something of them that I feel suit the purpose of this site now. Along with that I will do what I can to post a bit more frequently about what I am doing or sharing more things.

No promises on things as usual, I’m sure my schedule is going to flip around again soon so we’ll see how things go from here. 🙂


About Me page has been updated!
Projects and Links page has been updated!

~ atom0s

Misc Tutorials I’ve Recently Written

Here are some various articles/tutorials I’ve written in the past ~2 years:

C# Loader Hooking With Mono.Cecil
Click Here!

Terraria 1.1.2 – Decompiling / Recompiling
Click Here!

Creating Packet Editor / Proxy In C#
Click Here!

TSGE – Terraria Save Game Editor
Click Here!

Terraria 1.1.2 – Dumping Data and Textures
Click Here!

Terraria 1.1.2 – Collector Edition Bunny
Click Here!

XNA Hooking Through Reflection / Reference
Click Here!

Terraria – Steamless Loading

Disclaimer: Usage of a method to load the game list this allows you to run without Steam. This means the game can be copied onto other machines without purchasing it. I do not condone in piracy. I simply made this because I was sick of Steam for a while. I take no responsibility in what you do with this information.

Since Terraria is a managed application, we can easily import it into a project and reference the main class. With this we can initiate an instance of the main class and effectively load the game through our own app. With this we can skip the entire launching method that is called by the application when it’s asked to start (Main(..)).

So in turn we land up with:

using System;
using System.IO;
using System.Reflection;
using Microsoft.Xna.Framework;

namespace tLock
{
#if WINDOWS || XBOX
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            // Set Terraria's Path..
            String strRealPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + "\Steam\steamapps\common\terraria"; //"C:\Program Files (x86)\Steam\steamapps\common\terraria";
            Directory.SetCurrentDirectory(strRealPath);

            // Run our game..
            var tLock = Assembly.GetExecutingAssembly().GetType("tLock.Hook", true, true);
            (Activator.CreateInstance(tLock) as Game).Run();
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            using (FileStream fStream = new FileStream("errorlog.txt", FileMode.CreateNew, FileAccess.ReadWrite))
            {
                using (StreamWriter sWriter = new StreamWriter(fStream))
                {
                    sWriter.Write(((Exception)e.ExceptionObject).Message);
                }
            }
        }
    }
#endif
}

Then we need to add our hook class which tells the game were to locate the content. This also allows you alter the game while it plays to do a ton of other stuff. (Not covered in this post though.)

Hook.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Terraria;

namespace tLock
{
    public class Hook : Terraria.Main
    {
        protected override void Initialize()
        {
            // Reset the content directory..
            Content.RootDirectory = Environment.CurrentDirectory + "\Content\";

            // Base initialization..
            base.Initialize();
        }

        protected override void LoadContent()
        {
            base.LoadContent();
        }

        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
        }
    }
}

Once compiled, drop in the same directory as Terraria.exe and use your app to launch the game. Tada~ no more Steam