09/2007 by Zadig.
Tools needed:
Introduction:
When Zeta 1.21 was released, MagnusSoft also released a live cd so that a lot
of people can try Zeta without having to purchase it. This is somehow similar
to what Be inc did when R5 was out. However MagnusSoft protected their software
better that Be to avoid that this release can be installed on a hard-drive.
We will see here what are these protections, and why a Zeta LiveCD can not
be installed on a hard-drive without modifications on a lot of files.
The first protection that will be discussed concerns the kernel. If you try to boot the live cd system from a hard-drive, you will get the following message:
This is a Demo CD, you aren't supposed to use it for any other purpose.By the way this is not completely true since you will have to do the step 3 before getting this message. By disassembling the kernel and searching for this string we find this first protection:
Function mount_volumes 000310e9: a16ce10800 mov 0x8e16c,%eax 000310ee: 83e003 and $0x3,%eax ; mask value with 3 000310f1: 83f803 cmp $0x3,%eax : compare result this 3 000310f4: 7417 je 3110d ; continue if value == 3 Reference to string "/boot" ; else unmount and print error message 000310f6: 686cc00700 push $0x7c06c Reference to function "unmount" 000310fb: e81c7b0200 call 58c1c Reference to string "This is a Demo CD, you aren't supposed to use it for any other purpose." 00031100: 68e0c90700 push $0x7c9e0 Reference to function "panic" 00031105: e866000000 call 31170 0003110a: 83c408 add $0x8,%espAs you can see the value at "0x8e16c" is checked against the value "3". This value is filled just before:
Reference to object "fs.114" 00031085: 6860e10800 push $0x8e160 ; our object (0x8e16c) Reference to string "/boot" 0003108a: 686cc00700 push $0x7c06c 0003108f: 6aff push $0xffffffff 00031091: 6a00 push $0x0 00031093: 6aff push $0xffffffff 00031095: 6a01 push $0x1 Reference to function "sys_rfsstat" ; get stat information on boot directory 00031097: e878f50100 call 50614the fs.114 object type is probably fs_info that can be found in "kernel/fs_info.h":
#define B_FS_IS_READONLY 0x00000001
#define B_FS_IS_REMOVABLE 0x00000002
#define B_FS_IS_PERSISTENT 0x00000004
#define B_FS_IS_SHARED 0x00000008
#define B_FS_HAS_MIME 0x00010000
#define B_FS_HAS_ATTR 0x00020000
#define B_FS_HAS_QUERY 0x00040000
struct fs_info {
dev_t dev; /* fs dev_t */
ino_t root; /* root ino_t */
uint32 flags; /* file system flags */
off_t block_size; /* fundamental block size */
off_t io_size; /* optimal io size */
off_t total_blocks; /* total number of blocks */
off_t free_blocks; /* number of free blocks */
off_t total_nodes; /* total number of nodes */
off_t free_nodes; /* number of free nodes */
char device_name[128]; /* device holding fs */
char volume_name[B_FILE_NAME_LENGTH]; /* volume name */
char fsh_name[B_OS_NAME_LENGTH];/* name of fs handler */
};
As you can see the kernel checks for the values B_FS_IS_READONLY and
B_FS_IS_REMOVABLE of the flags field. This field is at offset 12 since dev_t is
32bits and ino_t is 64bits. If the device is not read-only AND removable, then
the kernel will not boot. So a first needed modification to boot on a hard-drive
is to force the jump at address 0x310a1 to avoid the read-only/removable test on
the boot device. However this will not be enought to make Zeta live cd boot.
The second protection is more evolved: A lot of binaries are protected so that they exit if the boot device is not read-only. This is the same behaviour than the kernel exept that the applications will silently exit. Such a behaviour is harder to detect since the binaries just close themself with no notification. This makes the system freeze during startup without any error. All these binaries contain the following code that is executed at startup:
Function BPrivate::ZInitializer::ZInitializer(void) ... Reference to string "/boot" 00000ff0: 50 push %eax Reference to function "dev_for_path" 00000ff1: e8c2f8ffff call 8b8 ; get device for boot directory 00000ff6: 89c2 mov %eax,%edx 00000ff8: 8d8520feffff lea 0xfffffe20(%ebp),%eax 00000ffe: 50 push %eax 00000fff: 52 push %edx Reference to function "fs_stat_dev" 00001000: e803f9ffff call 908 ; get stat on boot directory 00001005: 8a852cfeffff mov 0xfffffe2c(%ebp),%al 0000100b: 3401 xor $0x1,%al 0000100d: 83c40c add $0xc,%esp 00001010: a801 test $0x1,%al ; boot directory is read-only ? 00001012: 743b je 104f ; then continue execution ... else exit application ... Referenced by (conditionnal) jump(s) at Address(es): 00001012 0000104f: 8b4508 mov 0x8(%ebp),%eax ; param 0 (Object handle) 00001052: 8b9d1cfeffff mov 0xfffffe1c(%ebp),%ebx 00001058: 89ec mov %ebp,%esp 0000105a: 5d pop %ebp 0000105b: c3 ret 0000105c: 8b1c24 mov (%esp,1),%ebx 0000105f: c3 ret
As you can see the application checks that the boot directory is on a read-only device (1 is B_FS_IS_READONLY). There are several solutions to remove such a protection:
/* this function tells if the loaded objects contanins the protection at the
* specified offset */
int is_file_patchable(elfshobj_t *ps_ElfObj, uint32 i_FuncOffset)
{
uint32 i_ret;
char sz_Pattern[PATTERN_SIZE] = { 0x34, 0x01, 0x83, 0xc4, 0x0c, 0xa8,
0x01, 0x74, 0x3b, 0x6a, 0x00};
char sz_FilePattern[PATTERN_SIZE];
uint32 i_PatternOffset = 0x37;
i_ret = elfsh_raw_read(ps_ElfObj, i_FuncOffset + i_PatternOffset,
sz_FilePattern, PATTERN_SIZE);
if(i_ret != PATTERN_SIZE)
return(0);
if(memcmp(sz_Pattern, sz_FilePattern, PATTERN_SIZE) == 0)
return(1);
return(0);
}
/* this function patches a loaded object at the specified location */
int file_patch(char *sz_FileName, uint32 i_FuncOffset)
{
int32 i_ret;
FILE *f_File;
if( (f_File = fopen( sz_FileName, "r+")) == NULL )
return(-1);
i_ret = fseek( f_File, i_FuncOffset + PATCH_OFFSET, SEEK_SET);
if(i_ret)
{
fclose(f_File);
return(-1);
}
/* replace conditional jump with an unconditional one */
fputc(0xEB, f_File );
fclose(f_File);
return(0);
}
int main(int argc, char *argv[])
{
/* this is the mangled name of the function where is the protection */
char sz_InitFunc[] = "__Q28BPrivate12ZInitializer";
uint32 i_FuncOffset;
elfshobj_t *ps_ElfObj;
elfsh_Sym *ps_Function;
if(argc != 2)
{
printf("Usage: filepatch [filename]");
return(-1);
}
/* open file and ensure that it is an elf file */
ps_ElfObj = elfsh_load_obj(argv[1]);
if(ps_ElfObj == NULL)
return(-1);
/* search for the init function */
ps_Function = elfsh_get_symbol_by_name(ps_ElfObj, sz_InitFunc);
if(ps_Function == NULL)
{
ps_Function = elfsh_get_dynsymbol_by_name(ps_ElfObj, sz_InitFunc);
if(ps_Function == NULL)
{
printf("Init function not found in file '%s'\n", argv[1]);
elfsh_unload_obj(ps_ElfObj);
return(-1);
}
}
/* check that the function is correct */
i_FuncOffset = elfsh_get_symbol_value(ps_Function);
i_FuncOffset = elfsh_get_foffset_from_vaddr(ps_ElfObj, i_FuncOffset);
if(is_file_patchable(ps_ElfObj, i_FuncOffset) == 0)
{
elfsh_unload_obj(ps_ElfObj);
return(-1);
}
/* and patch the file */
if(file_patch(argv[1], i_FuncOffset) != 0)
{
elfsh_unload_obj(ps_ElfObj);
return(-1);
}
printf("File '%s' successfully patched\n", argv[1]);
elfsh_unload_obj(ps_ElfObj);
return(0);
}
This program can be called by a shell script that will search for all executable files in the system directories. Such a tool shows that there are about 500 binaries that are protected this way; These are probably all binaries that have been recompiled for the live cd release. This code has certainly been added by a special gcc version when the binaries have been generated.
In order to get a fully working zeta system some other manipulations are needed:
The live cd does not contain a bfs add-on on the "/boot/beos/system/add-ons/drive_setup" directory. This is why the live cd can not mount bfs partitions, because the kernel can not detect bfs volumes. Copying the add-on of a zeta or even an R5 release will fix this.
Another important thing to do is to remove the link that is in "/boot/home/config/settings", and rename the file "/boot/home/config/settings2" to settings. Without this, the kernel does not want to boot on the partition. This may be due to the fact that the kernel can not follow symbolic links at early stage during the boot, and that it requires several files (maybe the kernel settings ?).
A second modification is also necessary in the settings directory: There is a vesa settings file in "/boot/home/config/settings/kernel/drivers". It seems that the presence of this file forces zeta to boot in vesa mode. Removing it will allow to use accelerated drivers. This point is quite strange because I did not find a place where this file is removed when booted from cd. However the accelerated drivers are being used when booted this way.
A final modification is to remove the "/boot/beos/etc" link, and rename "/boot/bos/etc2" to etc. This modification is not necessary for the system to work but will remove an unnecessary link.
As you can see the MagnusSoft protections can be bypassed, but by more
sofisticated ways than with R5. However these protections can be considered as
"efficient" in the way that simple hacks do not work here: replacing the kernel
with the one from another release will not be enough for example. This
successfully prevented BeOS geeks to easily install the LiveCd release on a
hard-drive.
Zadig.