I'm hacking a game in my library (Mirror's Edge) to re-route where the save data is located. I've done this with many other games successfully, but this one has me stumped. Normally, I start with HxD and search for standard or unicode strings. If I can't find the string I'm looking for with a simple program like HxD, I move to more advanced programs like OllyDbg. In OllyDbg I use either the memory map or I search for all referenced strings in the CPU window. The game was obfuscated and had protection initially but I have since (successfully) removed it. I can't find the string with any of the methods I know, is there another tool or options with HxD or OllyDbg that can find strings that are stored differently?

Currently the game saves it's data in:

%USERPROFILE%\Documents\EA Games\Mirror's Edge
  • maybe try to locate methods that operate on paths and see how the value is populated to them? Maybe it will give you the clue where to look form them. Commented Dec 30, 2017 at 14:01
  • That sounds promising, but I wouldn't know where to start with that... I apologize, I'm still a novice at OllyDbg. I know this isn't a "Give me my answer" website but could you point me in the right direction perhaps? Commented Dec 30, 2017 at 15:47
  • well, I whodunit use Olly for that. Probably with some disassembler, I would check imports for some known API that operates on paths, from that found out the addresses and maybe then put bps on those in Olly and debug. Commented Dec 30, 2017 at 18:14

1 Answer 1


there are API's that are required to write to a file
an example of documented apis used to open and write to a file are file open -> kernel32.CreateFile file write -> kernel32!WriteFile

these apis require kernelmode transition and it happens at ntdll.NtCreateFile and ntdll!NtWriteFile

you can use ctrl+g in ollydbg to follow these apis and set a breakpoint there

assuming you have a file open an file write as in code below

#include <stdio.h>
#include <string.h>
void main(void) {
    char *foo = "lets open a file and write in it something\n";
    FILE *fp =NULL;    
    if((fp = fopen("c:\\somewrite.text" , "wb")) != NULL) {
        printf("we wrote this %s\n" , foo);

open the compiled exe in ollydbg v2.0

ctrl+g -> ntdll.NtCreateFile -> follow -> f2-> f9

you should break here

CPU Stack
Address  Comments
ESP ==>  ; /RETURN to KERNELBASE.CreateFileW+1D1
ESP+4    ; |Arg1 = 26F614
ESP+8    ; |Arg2 = 40100080
ESP+C    ; |Arg3 = 26F5B8
ESP+10   ; |Arg4 = 26F5FC
ESP+14   ; |Arg5 = 0
ESP+18   ; |Arg6 = 80
ESP+1C   ; |Arg7 = 3
ESP+20   ; |Arg8 = 5
ESP+24   ; |Arg9 = 60
ESP+28   ; |Arg10 = 0
ESP+2C   ; \Arg11 = 0

ZwCreateFile is Documented as

NTSTATUS ZwCreateFile(
  _Out_    PHANDLE            FileHandle,
  _In_     ACCESS_MASK        DesiredAccess,
  _In_     POBJECT_ATTRIBUTES ObjectAttributes,
  _Out_    PIO_STATUS_BLOCK   IoStatusBlock,
  _In_opt_ PLARGE_INTEGER     AllocationSize,
  _In_     ULONG              FileAttributes,
  _In_     ULONG              ShareAccess,
  _In_     ULONG              CreateDisposition,
  _In_     ULONG              CreateOptions,
  _In_opt_ PVOID              EaBuffer,
  _In_     ULONG              EaLength

the third argument is Pointer to _OBJECT_ATTRIBUTES which has a member ObjectName which is a pointer to _UNICODE_STRING

typedef struct _OBJECT_ATTRIBUTES {
  ULONG           Length;
  HANDLE          RootDirectory;
  ULONG           Attributes;
  PVOID           SecurityDescriptor;
  PVOID           SecurityQualityOfService;

typedef struct _UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR  Buffer;

so 0x26f5b8 is pointer to OBJECT_ATTRIBUTES

CPU Dump
Address   Hex dump                                         ASCII
0026F5B8  18 00 00 00|00 00 00 00|F4 F5 26 00|42 00 00 00|        ôõ& B
0026F5C8  00 00 00 00|E0 F5 26 00|                             àõ&

the third member of this struct 0x0026f5f4 is a pointer to unicode string

CPU Dump
Address   Hex dump                                         ASCII
0026F5F4  2A 00 1A 02|88 99 40 00|                         * ˆ™@

the wide char buffer is 0x00409988

CPU Dump
Address   Hex dump                                         ASCII
00409988  5C 00 3F 00|3F 00 5C 00|63 00 3A 00|5C 00 73 00| \ ? ? \ c : \ s
00409998  6F 00 6D 00|65 00 77 00|72 00 69 00|74 00 65 00| o m e w r i t e
004099A8  2E 00 74 00|65 00 78 00|74 00 00 00|             . t e x t

you can use follow in dump to follow and find the path you can look at the call stack using ctrl+k and locate function that may manipulate or create the paths prior to this

you can also use this shortcut for this specific function when you have broken on this API in dump window type ctrl+g and type in [[[esp+c]+8]+4] deference third argument (esp+c) then deference the third member and then deference the second member

  • Thank you @blabb for your answer. I apologize for the late response, some of this is beyond my skill set in OllyDbg but I plan on returning to this when I have more experience in the program. Commented Jan 10, 2018 at 23:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.