Freearc And Dark Souls 3

06 Jul 2017

In my free time I work on lots of small projects. One of those is called DarkSouls3.TextViewer and it lets you view all dialogue and item descriptions in Dark Souls 3:

DarkSouls3.TextViewer

To do this you have to extract the contents of Data1.bdt, which can be done with BinderTool by Atvaark. However, recently I got interested in possible changes made to item descriptions during updates, so I went on a hunt for all versions of Data1.bdt. Because Steam does not allow you to downgrade the game versions I started looking for pirated releases and updates to try to piece everything together. I downloaded Dark.Souls.III.The.Ringed.City-CODEX to get started, but then I noticed that I was too low on disk space to install the game…

InnoSetup

A quick look at setup.exe with ProtectionID reveals that it is an InnoSetup installer:

inno setup

There are several free tools available (innoextract, innounp) to see what’s inside:

>innoextract.exe -l e:\setup.exe
Listing "Dark Souls III The Ringed City" - setup data version 5.5.0.1 (unicode)
 - "tmp\ISDone.dll" [temp] (446 KiB)
 - "tmp\english.ini" [temp] (15.4 KiB)
 - "tmp\Style.vsf" [temp] (44.7 KiB)
 - "tmp\VclStylesinno.dll" [temp] (1.95 MiB)
 - "tmp\BASS.dll" [temp] (107 KiB)
 - "tmp\bp.dll" [temp] (129 KiB)
 - "tmp\wintb.dll" [temp] (27.5 KiB)
 - "tmp\Music.ogg" [temp] (2.34 MiB)
 - "tmp\Play1.bmp" [temp] (540 B)
 - "tmp\Play2.bmp" [temp] (540 B)
 - "tmp\Play3.bmp" [temp] (540 B)
 - "tmp\Pause1.bmp" [temp] (540 B)
 - "tmp\Pause2.bmp" [temp] (540 B)
 - "tmp\Pause3.bmp" [temp] (540 B)
 - "tmp\trackBkg.bmp" [temp] (776 B)
 - "tmp\trackbtn1.bmp" [temp] (344 B)
 - "tmp\trackbtn2.bmp" [temp] (344 B)
 - "tmp\trackbtn3.bmp" [temp] (344 B)
 - "tmp\unarc.dll" [temp] (368 KiB)
Warning: "setup-1.bin" is not part of the installer!
Use the --gog option to try listing the contents of this file.
Done with 1 warning.

The setup-1.bin file starts with ArC, so I checked the exports of unarc.dll and one that stands out is called FreeArcExtract, which points to FreeArc.

I tried to list the files in the archive, but the file format appears to be customized (or an older version):

>unarc l e:\setup-1.bin
FreeArc 0.67 unpacker
ERROR: archive structure corrupted (descriptor failed CRC check)

FreeArc

Then I thought, perhaps I can use unarc.dll from the setup to extract the relevant files? The lead is the name of the export FreeArcExtract. A bit of Googlefoo pointed to the relevant code, which looks like this:

int __cdecl FreeArcExtract (cbtype *callback, ...)
{
  va_list argptr;
  va_start(argptr, callback);

  int argc=0;
  char *argv[1000] = {"c:\\unarc.dll"};  //// Здесь будет искаться arc.ini!

  for (int i=1; i<1000; i++)
  {
    argc = i;
    argv[i] = va_arg(argptr, char*);
    if (argv[i]==NULL || argv[i][0]==0)
      {argv[i]=NULL; break;}
  }
  va_end(argptr);

  COMMAND command (argc, argv);    // Распарсить команду
  if (command.ok) {                // Если парсинг был удачен и можно выполнить команду
    command.Prepare();
    CThread thread;
    DLLUI *ui = new DLLUI(&command);
    thread.Create (timer_thread,      ui);   //   Спец. тред, вызывающий callback 100 раз в секунду
    thread.Create (decompress_thread, ui);   //   Выполнить разобранную команду

    for(;;)
    {
      ui->DoEvent.Lock();
      if (strequ (ui->what, "quit"))
        return ui->n1;  // error code of command
      ui->result = callback (ui->what, ui->n1, ui->n2, ui->str);
      ui->EventDone.Signal();
    }
    thread.Wait();
  }
  return command.ok? FREEARC_OK : FREEARC_ERRCODE_GENERAL;
}

Basically what this does is forward all the input parameters as the argv of unarc. After a lot of fooling around with the awfulness of va_list and lots of crashes I finally got the code to forward argv to the FreeArcExtract function:

#include <windows.h>
#include <cstdio>

#define whut(x) (strcmp(what, #x) == 0)

static int __stdcall cbExtract(char* what, int int1, int int2, char* str)
{
    if(whut(read) || whut(write))
        return 0; //filter out the plentiful "read" and "write" messages
    printf("\"%s\", %d, %d, \"%s\"\n", what, int1, int2, str);
    return 0;
}

typedef int __stdcall cbtype(char* what, int int1, int int2, char* str);
typedef int __cdecl pFreeArcExtract(cbtype* callback, ...);

int main(int argc, char* argv[])
{
    auto hMod = LoadLibraryA("unarc.dll");
    if(!hMod)
    {
        puts("Failed to load DLL: unarc.dll!");
        return 1;
    }
    auto FreeArcExtract = (pFreeArcExtract*)GetProcAddress(hMod, "FreeArcExtract");
    if(!FreeArcExtract)
    {
        puts("Failed to find export: FreeArcExtract");
        return 1;
    }
    auto a = [&](int i)
    {
        return i < argc ? argv[i] : "";
    };
    return FreeArcExtract(cbExtract, a(1), a(2), a(3), a(4), a(5), a(6), a(7), a(8), a(9), a(10), nullptr);
}

First I tried to get the help with unarc_cmd.exe, but this came up empty. Instead I asked unarc.exe:

>unarc
FreeArc 0.67 unpacker  http://freearc.org  2014-03-16
Usage: unarc command [options] archive[.arc] [filenames...]
Available commands:
  l - display archive listing
  v - display verbose archive listing
  e - extract files into current directory
  x - extract files with pathnames
  t - test archive integrity
... (more irrelevant options)

Then I tried to list all the files in the archive, which did not give me the output I expected at all (but hey, at least no CRC errors):

>unarc_cmd.exe l e:\setup-1.bin
"total_files", 283, 0, ""
"origsize", 25527, 998151285, ""
"compsize", 25096, 545797223, ""

The v option also came up empty, but the t option had more promise:

>unarc_cmd t e:\setup-1.bin
"total", 25096, 545800879, ""
"filename", 0, 810208, "Game\Data0.bdt"
"filename", 922, 967053390, "Game\Data1.bdt"
"filename", 2450, -1724920912, "Game\Data2.bdt"
... (it takes a few minutes to test all files)

To extract Data1.bdt, BinderTool also needs a file with decryption keys called Data1.bhd, so I used the following command to extract both those files:

>unarc_cmd x e:\setup-1.bin Data1.bdt Data1.bhd
"total", 25096, 545800879, ""
"filename", 0, 810208, "Game\Data0.bdt"
"overwrite?", 922, 967053390, "Game\Data1.bdt"
"filename", 922, 967053390, "Game\Data1.bdt"
"filename", 2450, -1724920912, "Game\Data2.bdt"
"filename", 1474, 1546563828, "Game\Data3.bdt"
"filename", 1172, 1229026224, "Game\Data4.bdt"
"filename", 13172, 927431435, "Game\Data5.bdt"
"filename", 1551, 1626443628, "Game\DLC1.bdt"
"filename", 2929, -1222753793, "Game\DLC2.bdt"
"filename", 0, 2212, "Game\Data0.bhd"
"filename", 0, 411904, "Game\Data1.bhd"

Conclusion

Well, I hope this was interesting to some people. It was just a 45 minute side project of mine that I decided to share.

If anyone has 魔法うんちく_dlc2.fmg from before the description of the White Birch Bow was changed, please ping me (the CODEX release is from after the update apparently).

Leave a comment

Cmake Openssl And Mingw On Windows

01 Apr 2017

If you found this you are probably having issues linking OpenSSL to MinGW-w64 using CMake (or CLion) on Windows. In this post I will give a quick overview on how to get this to work on a clean Windows machine…

The distribution I used to get it to work is Win64OpenSSL-1_2_2k.exe. The issue was that there are no MinGW-compatible link libaries. To solve this you can use my genlib tool to generate them:

cd c:\OpenSSL-Win64
set PATH=%PATH%;c:\genlib

genlib ssleay32.dll
genlib libeay32.dll

copy *.a lib\

The CMakeLists.txt looks like this:

# Project configuration
cmake_minimum_required(VERSION 2.7)
project(OpenSSLTest)

# Use C++11
set(CMAKE_CXX_STANDARD 11)

# Project source files
set(SOURCE_FILES main.cpp)
add_executable(OpenSSLTest ${SOURCE_FILES})

# OpenSSL (find, include, link) 
find_package(OpenSSL REQUIRED)
include_directories(${OPENSSL_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${OPENSSL_LIBRARIES})

And some simple test code:

#include <iostream>
#include <openssl/ssl.h>

int main() {
    std::cout << "SSLeay Version: " << SSLeay_version(SSLEAY_VERSION) << std::endl;
    SSL_library_init();
    auto ctx = SSL_CTX_new(SSLv23_client_method());
    if (ctx) {
        auto ssl = SSL_new(ctx);
        if (ssl) {
            std::cout << "SSL Version: " << SSL_get_version(ssl) << std::endl;
            SSL_free(ssl);
        } else {
            std::cout << "SSL_new failed..." << std::endl;
        }
        SSL_CTX_free(ctx);
    } else {
        std::cout << "SSL_CTX_new failed..." << std::endl;
    }
}

If everything is configured correctly this should print:

SSLeay Version: OpenSSL 1.0.2k  26 Jan 2017
SSL Version: TLSv1.2

If you cannot be bothered to run genlib yourself, you can find a copy the required files here and get started immediately.

Hope this helped,

Duncan

Leave a comment

My Inactivity

22 Sep 2016

Currently I do not have much time to update this blog because I am writing for the x64dbg blog, check it out!

Duncan

Leave a comment

Github Gpg

30 May 2016

Hello everyone,

Today I saw this broadcast on Github which states that GPG signature verification was added to Github. It took me a bit of searching before I got it to work from both the command line and Git Extensions so in this guide I will explain how I did it.

Installing Git (Extensions)

The first thing to install is the latest (v2.0.0+) version of Git for Windows.

After will have to install Git Extensions. Make sure to select the -SetupComplete but do not install MsysGit from there since you already installed a newer version.

Make sure you configure Git (Extensions) correctly so your identity is in sync with your Github email/username.

Installing GPG

You can download and install GPG from here. Next verify that you installed everything correctly:

C:\Users\Admin>git --version
git version 2.8.3.windows.1

C:\Users\Admin>gpg --version
gpg (GnuPG) 2.0.30 (Gpg4win 2.3.1)
libgcrypt 1.6.5
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: C:/Users/Admin/AppData/Roaming/gnupg
Supported algorithms:
Pubkey: RSA, RSA, RSA, ELG, DSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

If you get any errors, make sure you added everything to your PATH environment variable.

Generating GPG Keys

Follow this guide. In short:

C:\Users\Admin>gpg --gen-key
gpg (GnuPG) 2.0.30; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y

Real name: githubgpgtest
Email address: githubgpgtest@gmail.com
Comment:

gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
pub   4096R/6B84CA35 2016-05-30
      Key fingerprint = DF55 D8E3 B4E5 9614 7ADF  8E6E E5B6 4A58 6B84 CA35
uid       [ultimate] githubgpgtest <githubgpgtest@gmail.com>
sub   4096R/63BEB3EE 2016-05-30

Notice: I will be using 6B84CA35 as my identifier for my key, you should use your own in the upcoming commands.

Adding your key to Github

Follow this guide. In short:

C:\Users\Admin>gpg --list-keys
C:/Users/Admin/AppData/Roaming/gnupg/pubring.gpg
------------------------------------------------
pub   4096R/6B84CA35 2016-05-30
uid       [ultimate] githubgpgtest <githubgpgtest@gmail.com>
sub   4096R/63BEB3EE 2016-05-30


C:\Users\Admin>gpg --armor --export 6B84CA35
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2

mQINBFdMlawBEADUmBNVR8psLgeBQ1hz2N7VjVmiPiwbgpIK9VAToLX8BYl2ZPYB
...
=k1LJ
-----END PGP PUBLIC KEY BLOCK-----

Add your key to your Github account through this page:

github screenshot

Configuring Git

Set your globally installed GPG version in Git (make sure to alter this path if you installed gpg2.exe in a different location):

git config --global gpg.program "C:/Program Files (x86)/GNU/GnuPG/gpg2.exe"

Then set your generated signing key:

git config --global user.signingkey 6B84CA35

These commands enable automatic GPG signing for commits and tags (which is required if you want this to work with Git Extensions):

git config --global commit.gpgsign true
git config --global tag.gpgsign true

Now when commiting the Git Extensions it should show you the following dialog:

gpg password

After pushing to the repository Github shows your commits as verified:

verified

Conclusion

That’s about it, your passphrase should cache for a while so you shouldn’t be bothered with entering your passphrase every single time you commit. You can configure your caching times here:

gpg cache

The first entry is the default-cache-ttl option, the second max-cache-ttl:

--default-cache-ttl n
    Set the time a cache entry is valid to n seconds. The default is 600
    seconds.
--max-cache-ttl n
    Set the maximum time a cache entry is valid to n seconds. After this time a
    cache entry will be expired even if it has been accessed recently. The
    default is 2 hours (7200 seconds).

If you enjoyed this post, feel free to share it with your friends through social media.

Duncan

Leave a comment

Dynamic Menu Builder

03 Feb 2016

Hello folks,

While on the plane back home I decided to write another little blog post. This time I will be showing you a nice class I came up with for x64dbg to manage menu items.

The problem

As with every abstraction it starts with a problem you are trying to solve. In this case the problem was code duplication and general tediousness with the construction of the context (right click) menus in x64dbg.

The general idea of Qt is great. From my understanding, every context menu is a QMenu with a bunch of QAction or other QMenu items in it. When a user right-clicks in the widget a signal will be emitted and the widget can connect to the signal, construct the QMenu and ‘execute’ the menu on the mouse position. Each QAction has a signal called triggered() which you can connect to a slot in your widget to handle the click event.

If there is no variation in the menu everything works perfectly fine. You just create all the actions, menus and connections in the constructor and store the final QMenu item in the class. Then when you need the menu you do mMenu->exec(position) and you are done with it.

In x64dbg the menus are based on the context, so the static approach doesn’t work. What we did was create and connect all the QAction items in the constructor and then dynamically create the menu. What this did was create a lot of fragmentation. All the actions had to be declared in the header, the slots for the actions had to be declared in the header and the source and adding a new action would result in a lot of code that looked exactly like this:

mFollowAddress = new QAction("&Follow in Disassembler", this);
connect(mFollowAddress, SIGNAL(triggered()), this, SLOT(followAddress()));

For actions with a shortcut and an icon it was even worse:

mToggleBreakpoint = new QAction("Toggle Breakpoint", this);
mToggleBreakpoint->setShortcutContext(Qt::WidgetShortcut);
mToggleBreakpoint->setIcon(QIcon(":/images/icons/breakpoint.png"));
addAction(mToggleBreakpoint);
connect(mToggleBreakpoint, SIGNAL(triggered()), this, SLOT(toggleBreakpoint()));

Shortcuts also require setting the actual shortcut in a dedicated slot called refreshShortcutsSlot() which is connected to the settings dialog so shortcuts are updated when the user updates the settings:

void ReferenceView::refreshShortcutsSlot()
{
    mToggleBreakpoint->setShortcut(ConfigShortcut("ActionToggleBreakpoint"));
    mToggleBookmark->setShortcut(ConfigShortcut("ActionToggleBookmark"));
}

Finally the menu is created in contextMenuEvent like this:

if(!DbgMemIsValidReadPtr(addr))
        return;
wMenu->addAction(mFollowAddress);
wMenu->addAction(mFollowDumpAddress);
if(apiAddressFromString(mCurList->getCellContent(mCurList->getInitialSelection(), 1)))
    wMenu->addAction(mFollowApiAddress);
wMenu->addSeparator();
wMenu->addAction(mToggleBreakpoint);
wMenu->addAction(mToggleBookmark);

As you can imagine, adding an action with an icon, a shortcut and some context-dependent behaviour was a very tedious process and this needed to change.

Part of the solution is a MenuBuilder class. This is a recursive datatype (like QMenu) but it lazily builds the menu, which allows for proper context-awareness.

To achieve context-awareness, each QAction/QMenu/MenuBuilder you add to a MenuBuilder is paired with an std::function. If the callback returns true, the item is added to the final QMenu, otherwise it is ommitted. This allows for constructs like this:

mBuilder->addAction(followAction, [this](QMenu* menu)
{ //only add followAction if the selected address is readable.
    return DbgMemIsValidReadPtr(this->selectedAddress());
});

The followAction will only be added to the final QMenu if the currently selected address is a valid memory address. This is a huge save in code, the menu creation slot can be replaced with:

QMenu menu;
mBuilder->build(&menu);
menu.exec(pos);

There are some extra features (like using the menu parameter of the lambda to add extra actions to the final QMenu, but if you want more details, read the code here.

Actions

The next problem to solve is the creation of the QAction and QMenu items. The solution was to create a few simple helper methods in the base class (AbstractTableView):

template<typename T>
inline QAction* makeAction(const QString & text, T slot)
{
    return connectAction(new QAction(text, this), slot);
}

inline QAction* connectAction(QAction* action, const char* slot)
{
    connect(action, SIGNAL(triggered(bool)), this, slot);
    return action;
}

inline QAction* connectAction(QAction* action, QActionLambda::TriggerCallback callback)
{
    auto lambda = new QActionLambda(action->parent(), callback);
    connect(action, SIGNAL(triggered(bool)), lambda, SLOT(triggeredSlot()));
    return action;
}

The makeAction uses a template because I added lambda support to the actions. This is not in Qt 4 and rather simple to implemented so I decided to add it:

class QActionLambda : public QObject
{
    Q_OBJECT
public:
    typedef std::function<void()> TriggerCallback;

    QActionLambda(QObject* parent, TriggerCallback callback)
        : QObject(parent),
          _callback(callback)
    {
    }

public slots:
    void triggeredSlot()
    {
        if(_callback)
            _callback();
    }

private:
    TriggerCallback _callback;
};

Now to create an action you’d write:

makeAction("Selection (&No Bytes)", SLOT(copySelectionNoBytesSlot()))

And similarly an action with shortcut and icon:

makeShortcutAction(QIcon(":/icons/images/highlight.png"), "&Highlighting mode", SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode")

Final words

I guess that’s about it for this blog post. If you want to see what the final menu creation code looks like, check out the code here. For reference, the old code is available here, as you can tell it is a great improvement.

Finally, I know reader interaction has been practically non-existent on this blog so far, however it would be nice if you could send me parts of x64dbg you’d like to get insight in development-wise. Any other topics (reversing/programming) related are also welcome!

Greetings,

Duncan

Leave a comment