Archive

Posts Tagged ‘mimic’

Status update and some code

July 6th, 2009

Been quiet the last week because I’ve just moved house. Got everything sorted and up and running now though so I should be able to get some stuff done. I still plan to take a look at some of the bots on the market currently, but have just been so busy lately, and with Mimic already being half-way into their grave I didn’t really think it was urgent to push them in all the way, I think they can take care of that themselves.

Anyway, I figured I may as well post something of use so here’s a C++ logging class I posted on GD that may be of use to people*:

* I’ll post a version with some of the outlined problems fixed Soon. Just gotta get back into the swing of things, moving always shakes me up for a few days.

This is a C++ logging class designed to be both generic and portable. Currently needs fixes in order to be truly portable but I havn’t had time to reinstall G++ or Intel to test, I’ve outlined the minor issues though. If you want to fix the issues it’s a 10 minute job at most, I’m just lazy.

The idea is that you can redirect the standard output streams to a file using a generic class template (so when new character types are added like the ones in C++0x it will be much easier to add support).

This should work across operating systems (Linux, Mac, etc).. Anything with Boost support (which is all major OS’s) SHOULD work, but is untested. Obviously you’ll need to remove the MSVC specific pragmas.

Notes:
* Boost dependency. This will not work without Boost. No I will not help you install Boost, it’s not hard, just read the documentation. If you can’t get it working you probably shouldn’t be using C++.
* Minor modifications needed for it to be truly portable. (See below)
* Relative log file path is hardcoded to “../Logs/Hades-%s.log”. Simply change that to a relative path from your module.
* Compiler is assumed to be MSVC. I am using VS 2008 Team Edition with code analysis enabled. If you get an error about warning “6328″ not being valid simply remove the pragma line with that in it.
* If you are using a compiler other than MSVC you’ll want to remove the ‘pragma warning’ stuff, I’ll fix that later.
* Makes heavy use of templates. Unless you know what you’re doing its probably best to just leave all the typedefs and template stuff alone.

Usage:
Makes use of templates and the standard output streams.
For example:
// Logging objects
Logger<char>::Stream m_AnsiStream;
Logger<wchar_t>::Stream m_WideStream;
// Initialize logger
m_AnsiStream.open(Logger<char>());
std::cout.rdbuf(m_AnsiStream.rdbuf());
m_WideStream.open(Logger<wchar_t>());
std::wcout.rdbuf(m_WideStream.rdbuf());

Now, whenever you use cout or wcout like so:
std::cout << “Look ma, I’m using the standard output stream!” << std::endl;
std::wcout << L”Wide output too!”"<< std::endl;

The output will be redirected to your file rather than to the screen or wherever the standard output was aimed at previously.

Obviously your Logger objects need to remain valid whilst ever your program is running unless you manually reset the standard output stream buffers. This means that you should store them as static objects somewhere. If you store them as a local object then they will be destructed when they move out of scope and you’ll get an access violation.

An alternative to the above is to just heap-allocate the object. Its destructor will never be called but this is probably not a problem. The reason this may be better is that you avoid race conditions implicit in the order of destruction of static objects. Obviously do NOT use a smart pointer because at that point it WILL be deleted and you’re back where you started.

Misc:
You are free to use this for whatever, as long as you agree that Kynox’s sister is a nympho.

Code:

// Preprocessor header guard to stop multiple includes

#ifndef HADES__LOGGER_H

#define HADES__LOGGER_H

// C++ Standard Library

#include <iostream>

#include <string>

#include <vector>

#include <fstream>

// Boost C++ Libraries

#pragma warning(push, 1)

#pragma warning(disable: 6328)

#pragma warning(disable: 4996)

#pragma warning(disable: 4702)

#include <boost/iostreams/categories.hpp>

#include <boost/iostreams/stream.hpp>

#include <boost/date_time/posix_time/posix_time.hpp>

#include <boost/format.hpp>

#include <boost/filesystem.hpp>

#pragma warning(pop)

// Logging class

template <typename _charT>

class Logger

{

public:

// Sink information

typedef _charT char_type;

typedef boost::iostreams::sink_tag category;

// STL typedefs

typedef std::basic_ofstream<char_type> tofstream;

typedef std::basic_string<char_type> tstring;

// Boost typedefs

typedef boost::basic_format<char_type> tformat;

struct path_traits;

typedef boost::filesystem::basic_path<tstring, path_traits> tpath;

struct path_traits

{

typedef tstring internal_string_type;

typedef tstring external_string_type;

static external_string_type to_external( const tpath &,

const internal_string_type & src ) { return src; }

static internal_string_type to_internal(

const external_string_type & src ) { return src; }

};

// Stream typedef

typedef boost::iostreams::stream< Logger<_charT> > Stream;

// Constructor

Logger() : m_LogPath(GeneratePath())

{ }

// Generate path to log file.

tstring GeneratePath()

{

// For boost

using namespace boost::posix_time;

using namespace boost::filesystem;

using boost::str;

// For STL

using std::string;

using std::wstring;

// Get local time

ptime Time(second_clock::local_time());

// Convert time to string YYYY-MM-DDTHH:MM:SS

tstring TimeStr(to_iso_extended_string_type<char_type>(Time));

// Reformat time YYYY-MM-DD_HH-MM-SS

TimeStr[10] = ‘_’;

TimeStr[13] = ‘-’;

TimeStr[16] = ‘-’;

// Generate file path relative to initial directory

wstring WideFormat(L”../Logs/Hades-%s.log”);

tstring AnyFormat(WideFormat.begin(), WideFormat.end());

tstring RelPath(str(tformat(AnyFormat) %TimeStr));

// Make full path to log file

tpath Current(initial_path<tpath>());

Current /= RelPath;

// Return path to log file

return Current.string();

}

// Writes n characters from s

std::streamsize write(const char_type* s, std::streamsize n)

{

// For boost

using namespace boost::posix_time;

// Get time

ptime Time(second_clock::local_time());

tstring TimeStr = to_simple_string_type<char_type>(Time);

// Open file

tofstream Out(m_LogPath.c_str(), tofstream::out | tofstream::app );

if(Out.is_open() && Out.good())

{

// Write time as string

Out << ‘[' << TimeStr << "]: “;

// Write data

Out.write(s, n);

}

// Return size

return n;

}

private:

// Path to log file

tstring m_LogPath;

};

#endif // HADES__LOGGER_H

// Preprocessor header guard to stop multiple includes
#ifndef HADES__LOGGER_H
#define HADES__LOGGER_H
// C++ Standard Library
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
// Boost C++ Libraries
#pragma warning(push, 1)
#pragma warning(disable: 6328)
#pragma warning(disable: 4996)
#pragma warning(disable: 4702)
#include <boost/iostreams/categories.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#pragma warning(pop)
// Logging class
template <typename _charT>
class Logger
{
public:
// Sink information
typedef _charT char_type;
typedef boost::iostreams::sink_tag category;
// STL typedefs
typedef std::basic_ofstream<char_type> tofstream;
typedef std::basic_string<char_type> tstring;
// Boost typedefs
typedef boost::basic_format<char_type> tformat;
struct path_traits;
typedef boost::filesystem::basic_path<tstring, path_traits> tpath;
struct path_traits
{
typedef tstring internal_string_type;
typedef tstring external_string_type;
static external_string_type to_external( const tpath &,
const internal_string_type & src ) { return src; }
static internal_string_type to_internal(
const external_string_type & src ) { return src; }
};
// Stream typedef
typedef boost::iostreams::stream< Logger<_charT> > Stream;
// Constructor
Logger() : m_LogPath(GeneratePath())
{ }
// Generate path to log file.
tstring GeneratePath()
{
// For boost
using namespace boost::posix_time;
using namespace boost::filesystem;
using boost::str;
// For STL
using std::string;
using std::wstring;
// Get local time
ptime Time(second_clock::local_time());
// Convert time to string YYYY-MM-DDTHH:MM:SS
tstring TimeStr(to_iso_extended_string_type<char_type>(Time));
// Reformat time YYYY-MM-DD_HH-MM-SS
TimeStr[10] = ‘_’;
TimeStr[13] = ‘-’;
TimeStr[16] = ‘-’;
// Generate file path relative to initial directory
wstring WideFormat(L”../Logs/Hades-%s.log”);
tstring AnyFormat(WideFormat.begin(), WideFormat.end());
tstring RelPath(str(tformat(AnyFormat) %TimeStr));
// Make full path to log file
tpath Current(initial_path<tpath>());
Current /= RelPath;
// Return path to log file
return Current.string();
}
// Writes n characters from s
std::streamsize write(const char_type* s, std::streamsize n)
{
// For boost
using namespace boost::posix_time;
// Get time
ptime Time(second_clock::local_time());
tstring TimeStr = to_simple_string_type<char_type>(Time);
// Open file
tofstream Out(m_LogPath.c_str(), tofstream::out | tofstream::app );
if(Out.is_open() && Out.good())
{
// Write time as string
Out << ‘[' << TimeStr << "]: “;
// Write data
Out.write(s, n);
}
// Return size
return n;
}
private:
// Path to log file
tstring m_LogPath;
};
#endif // HADES__LOGGER_H
Author: Cypherjb Categories: Games, Programming Tags: , , , , , ,

Update on Mimic

June 19th, 2009

Hey, as most of the people interested in the Mimic saga already know, a new version is out.  A bunch of people have contacted me to ask if I would be posting about it, so I figured I’d post an explanation as to why I may or may not be. Kynox has done a minor coverage of the update available here.

I may or may not do a full and in-depth coverage for three reasons:

  1. I think it has been proven beyond doubt now that Mimic is indeed full of shit when it comes to their anti-anti-cheat code.
  2. I think they have been given enough handouts for now.
  3. Working on my new project is simply much more fun.

That being said, if I get bored I might take a look at the changes, but all I will be doing is documenting them, and pointing out whether it as a whole is still detectable. I will no longer be handing them free anti-warden ideas, they’re on their own now.

WoWMimic v50

June 11th, 2009

Another WoWMimic build was released recently. I’ve reversed it yet again to bring you the gory details.

They’ve beefed up (by their standards) the obfuscation on this one. I put “by their standards” because they’re morons, and by the standards of any real reverser ‘beefed up’ is hardly the right term. It seems they’ve learned two new ‘tricks’, one they use once, another they use constantly. Both are very lame and very obvious and easy to undo though.

The first is this:

15DEBE67 | 5B            | POP     EBX                         | ; Pop address of current line into EBX

15DEBE68 | 81EB 471A4000 | SUB     EBX, 401A47                 | ; Subtract 401A47 from EBX (15DEBE67) (Final: 159EA420)

15DEBE6E | 8B83 F1194000 | MOV     EAX, DWORD PTR [EBX+4019F1] | ; Move 7CCAE98C into EAX

15DEBE74 | 35 8CE9CA7C   | XOR     EAX, 7CCAE98C               | ; Xor EAX (7CCAE98C) with 7CCAE98C. (Final: 0)

15DEBE79 | 8D8B C81A4000 | LEA     ECX, DWORD PTR [EBX+401AC8] | ; Move EBX (159EA420) + 401AC8 into ECX (Final: 15DEBEE8)

15DEBE7F | 8D0401        | LEA     EAX, DWORD PTR [ECX+EAX]    | ; Move ECX (15DEBEE8) + EAX (0) into EAX (Final: 15DEBEE8)

15DEBE82 | FFE0          | JMP     NEAR EAX                    | ; Jump NEAR to EAX (15DEBEE8). Another obfuscation attempt.

They have attempted to hide the jump address with some VERY basic math. Sorry guys, but you’re gonna have to do better than that.

Second trick:

; MimicVectoredHandler

15DEBE06 | 55            | PUSH    EBP       | ; Standard stack frame setup

15DEBE07 | 8BEC          | MOV     EBP, ESP  | ; Standard stack frame setup

15DEBE09 | 81C4 00FFFFFF | ADD     ESP, -100 | ; Sub ESP 100. Room for local variables

15DEBE0F | EB 50         | JMP     15DEBE61  | ; Jump over garbage and into an instruction. Obfuscation attempt.

; Original - Nice try… Not!

15DEBE60 | 2A60 E8 | SUB     AH, BYTE PTR [EAX-18] | ; Jump lands one byte into this instruction.

15DEBE63 | 0000    | ADD     BYTE PTR [EAX], AL    | ; Just reassemble the bytes to fix it.

15DEBE65 | 0000    | ADD     BYTE PTR [EAX], AL    | ; See below for one I prepared earlier!

; Fixed - Wow.. that was hard…

15DEBE61 | 60          | PUSHAD           | ; Preserve registers

15DEBE62 | EB 00000000 | CALL    15DCBE67 | ; Call next line

They’re attempting to confuse disassemblers by jumping into what seems to be the middle of an instruction. What they don’t seem to realize is that there are two very easy ways to undo this. One is to realign your disassembler for that chunk if it has that functionality. The other is to just dump out the bytes, assemble them externally (in OllyDbg or another tool that can assemble bytes into mnemonics), and just read from there.  Thanks to Nessox and Apoc for doing that for me because Olly was being a whore on my PC.  To put it simply, its no barrier to any reverser with half a brain.

Both obfuscation ‘techniques’ (if you can call them that) just reek of the work of an amateur. I still think they’re waiting for “one of china’s best hackers” to turn up for work.

As for actual changes to the implementation, there isn’t much, they seem to have wasted the last week or so on obfuscation which took them 1000x longer to write than it took me to reverse. Nevertheless, there is one notable change, which is to their ZwQueryVirtualMemory hook.

They no longer null out pMemoryBasicInformation->BaseAddress, but they have started nulling out pMemoryBasicInformation->RegionSize. The reason for this is both obvious and hilarious.

The previous build of WardenMimic (new one coming once I get some free time) worked by enumerating all regions of memory to look for the one that has been hidden. It is identified by detecting the unique return values which would never be returned in normal circumstances. Whilst the change breaks WardenMimic, it does so for all the wrong reasons. Not only do they obviously have no idea how a NtQueryVirtualMemory hook is actually supposed to work, they’ve fucked up and left another gaping hole AGAIN. That’s right, the hook is STILL detectable by Warden because the morons obviously don’t understand the first thing about Windows internals and virtual memory.

The rest of the APIs (GetCursorPos, SetCursorPos, NtGetContextThread) remain unhooked for the time being. (GetCursorPos and SetCursorPos still have the bug that was left there from the previous build.)

So, in summary, the changes are as followed:

  • Had another crack at obfuscating their anti-detection code and failed hard.
  • Attempted to fix their NtQueryVirtualMemory hook. Whilst they broke WardenMimic they fucked up their hook AGAIN and so Mimic is STILL DETECTABLE.

It’s pretty funny it took them this long just to push out such a simple new build. Really says something about either the quality of the developers or the quality of the customer service department. (Regardless though, the fail obfuscation attempts definitely say something about the developers. — In case you’re slow, its says they’re incompetent.)

Full code (with documentation) is available again. Anything marked as “Fixed” has been realigned so most of the obfuscation will not be apparent unless you reverse it yourself.

WoWMimic v50 Anti-Detection Code.

WoWMimic PvPAdvance v14

May 29th, 2009

Bored, so I took a look at the new version of WoWMimic PvPAdvance to see what they changed. Unfortunately v13 wouldn’t run on my PC,  so I don’t have anything to base it off, but when the next version comes out at least I will. I’m not surprised at all that there have been bans for this tool, its anti-detection is even worse than WOWMimic itselfs.

What they’re currently doing:

  1. Unlinking the module.

No. Seriously. That seems to be it.

They’re not hooking VirtualQuery (or any of its lower-level code paths), and they’re not even nulling out their PE header. This means that a Warden scan that is CURRENTLY IMPLEMENTED can be used to detect their module, all the Warden dev needs to do is add a new hash.

My guess is that with the bans from the previous version they made minor changes to their code, which changed the module hash at the point Warden was scanning, noticed they weren’t getting bans anymore, and assumed they fixed the problem. That, or they’re too lazy to fix it properly. Either way they’re idiots.

Epic fail. Quite disappointing really, that only took a minute or two to check and now I’m bored again.