PDA

View Full Version : [template] new patching system by g3ggo



deadspot
17-02-2006, 07:17 AM
[template] new patching system

--------------------------------------------------------------------------------

ideas:

1. use C as programming language
- flexible, well-known language
- also used in nokix to compile the extensions for e.g. dct3 phones (games, apps...)
- can use the script also as source for a standalone patcher
- re-use many already existing functions in NokiX / g3n0lite / ARMada

2. not relying on a particular UI
- allows patches to be run via commandline parser or with win32 GUI without changes
- simple console interface for testing a patch

3. providing routines for data manipulation
- patch does not directly modify flash data, instead it calls patching routines
- these may track the changes that have been done (can be re-viewed by user)


example patch:

Code:
#include <patcher.h>

#pragma HEADER AUTHOR g3gg0
#pragma HEADER VERSION v0.01
#pragma HEADER DESCRIPTION "This is a simple demonstration script"

int debug = 0;
int testonly = 0;
int tries = 0;
char textbuf[513];

/*
these options are configurable after loading a patch script.
when using a GUI, there should be an options page for each script
before executing it.
in case of a text based client, you can either specify the options
via commandline in this manner:

./patcher -script testscript_a, testscript_b
-o 1,"debug=0","testonly=0","text=somewhere over the rainbow..."
-o 2,"debug=1","testonly=1","text=way up high"

this will pass the options
"debug=0" "testonly=0" "text=somewhere over the rainbow..."
to the 1st script etc.

or the options will be asked prior to executing the scripts
*/
ps_options options[] =
{
{ PS_OPT_BOOL, "Enable Debug messages", "debug", &debug },
{ PS_OPT_BOOL, "Don't modify data", "testonly", &testonly },
{ PS_OPT_INT, "Number of retries", "tries", &tries },
{ PS_OPT_STR, "Text to insert (max 512 chars)", "text", textbuf }
};

ps_pattern pat_foo =
{
"foofunc",
"\xB5\xF0\x20\x00\x21\x00\x49\x1A\x23\x0A\xBD\x00",
"\xFF\xFF\xFF\xFA\x00\xFF\xFF\x00\xFF\xFF\xFF\x00",
12,
PS_PAT_NOBACK // no "search back to B5xx" .... or simply 0
};

ps_pattern pat_bar =
{
"foobarfunc",
"\x49\x1A\x23\x0A\xBD\x00",
"\xFF\x00\xFF\xFF\xFF\x00",
6,
PS_PAT_BACK // "search back to B5xx" .... or simply 1
};

function func_test =
{
"new_function",
"\xB5\x00\x20\x00"
"\xF0\x00\xF8\x00"
"\xBC\x00",
10,
1,
{ 0x04 },
{ "func_something" }
};

int
patcher ( void )
{
ps_fileinfo *fileinfo = ps_get_fileinfo ();
unsigned long offset = 0;

/* optional, to be safe */
if ( fileinfo->filetype != PS_TYPE_DCT4 )
abort ( "Sorry, this is not a n* file" );
if ( fileinfo->filestate != PS_STATE_DECRYPTED )
abort ( "Please open the file with option 'serialize and decrypt' checked" );

int happy = ps_dlg_bool ( "Are you happy?" );
int age = ps_dlg_int ( "How old are you?", 0, 255 );
int status = ps_dlg_string ( "Whats your name?", textbuf, 512 );

if ( happy == PS_DLG_ERR || age == PS_DLG_ERR || status == PS_DLG_ERR )
{
ps_dlg_msg ( "Okay, you dont want to talk :(" );
return PS_OK;
}

offset = ps_locate ( pat_foo );
if ( offset == PS_NOTFND )
abort ( "Pattern foo not found" );

unsigned long newfunc = ps_create_func ( func_test, PS_AUTO ); /* automatically find space */
if ( newfunc == PS_NOTFND )
abort ( "Could not insert new routine - no space found :(" );

int state = ps_inject_bl ( offset, newfunc );
if ( state != PS_OK )
abort ( "Could not patch the foo routine" );


/* set bytes after PUSH to 0x20nn (MOV R0, nn)
automatically converts LE->BE since we work with nokia files
this decission is made by the patcher system when opening binary file
*/
ps_set ( newfunc+2, 0x20 | (age&0xFF) );

/* just for demo reasons */
if ( ps_get ( newfunc+2 ) & 0xFF < 0x10 )
printf ( "Wow, ure young ;)" );

return PS_OK;
}
of course, this is just a thought how it could be...
especially the function names and constants like PS_NOTFND etc have
to get some more lucky names.




i also thought about a segmentation and phase states of the fileinfo..


Code:
struct s_fileinfo
{
s_phase phase[10];
...
}

struct s_phase
{
char name[20];
s_segment segment[20];
unsigned long start_ofs;
unsigned long end_ofs;
}

struct s_segment
{
char name[20];
unsigned char* data;
unsigned long start_ofs;
unsigned long end_ofs;
}
so when opening a standard DCT4 flashfile, the will be 5 phases:

1. "original" = the original file in wintesla format - just one segment
2. "serialized" = the encrypted data in serialized format BUT with 2 segments:
- offset 0x0000 to 0x002C
- offset 0x0064 to [end]
as the original flashfile is not continuous but has a gap between 0x2C and 0x64 iirc
in case of a bluetooth phone, we have another segment:
- BT image
3. "decrypted" = the same segments as above, just the MCU decrypted, 2 or 3 segments
4. "encrypted" = as the name says, the sequence 3's MCU area encrypted again
5. "finished" = blockified again - just one segment again

in the patch script you can select your working target by calling
ps_workspace ( "decrypted" );
so every routine automatically will work with the sequence 3

i think this sequences are good because of:
- if we restrict the workspace to "decrypted", how may we patch PPM files which are not encrypted?
- when just patching the first 0x2C bytes, why should we need to decrypt and encrypt the whole MCU block?
- its totally up to the patch programmers mind what he wants to modify


if the programmer says ps_workspace("serialized") and modifies something
in the header (below 0x002C) and returns from patcher, we just have to
call the wintesla output routine and we're done.
if he has chosen "decrypted", we know we have to reencrypt the file again.

its much more complex if the user has to decide for each patch he applies,
what kind of data is needed... should the patcher serialize and decrypt it?
or just serialize? or should it do none of these?

with this method, the patch script will (must) decide - it knows the best,
what data it needs


about the segments:
if we fully support segments in the patcher, we will later have less pain when
we have to write the file back in wintesla format. i saw that the "dirty" all-in-one flashfile, we are used from dct3 is not a very good solution
and will especially hurt when using files of newer phones.

i thought "okay let's everything below 0x2C as an extra block" and had big
problems when suddenly 6230 etc had the gap between 0x012C and 0x0164.

of course will the patch script just call ps_set(0x20, 0) or ps_set(0x234, 0)
and the patcher will choose the correct segment for that address...
its generally a good idea to keep as much information about the original
file as possible (maybe also the chunksize as it differs between some phones)


maybe its also a very good base for patching ELF files, because it also
uses segments (as also MZ or PE)

EDIT:
hey i love this idea! yak, you have routines to parse the ELF sections?
with these routines and little work, it would not be a such big problem
to edit also ELF files and modify the segments......


yak, krisha, nokdoc?
what do you think about these ideas i had?
lets start brainstorming

for more info follow the link...http://www.gsmfreeboard.com/forum/showthread.php?t=121597