=-[ http://www.badchecksum.net ]-============================================ =-[ xlcpatch ]-===================================================-[ 2007 ]-= =-[ by ayesa ]-==================================-[ ayesa badchecksum net ]-= /* * * *ING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WA * * LICENSE: * * THIS TEXT IS FOR EDUCATIONAL PURPOSES ONLY! * IN NO CASE THIS TEXT ENCOURAGES THE READER TO CRACK * OR REVERSE ENGINEER PROPRIETARY SOFTWARE NOR COMMIT * CRIMES OF ANY TYPE. * THE AUTHOR IS NOT RESPONSIBLE FOR ANY DAMAGE CAUSED * TO YOUR HARDWARE/SOFTWARE BY FOLLOWING THE STEPS HERE DESCRIBED. * * * IF YOU DO NOT UNDERSTAND AND/OR AGREE TO THE ABOVE TERMS * DO NOT READ THIS TEXT! * *RNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - * * */ ------------------------------------------------------------------------------- AUTHOR: ayesa PUB. DATE: 03/06/07 LANGUAGE: English OS: AIX VERSION: 5.3 HARDWARE: POWER ------------------------------------------------------------------------------- BEFORE WE BEGIN ------------------------------------------------------------------------------- Symptom: # cc -o hallo hallo.c The license for the Evaluation version of IBM XL C/C++ Enterprise Edition V8.0 for AIX Compiler product has expired. You installed the trial version of this wonderful compiler suite and it has expired requiring you to purchase the license (heavy priced license, that is). This minihowto explains how to bypass this restriction with just some thinking, guess and tainting. Before you continue reading please make sure you have the following software already installed: Tracer: truss - AIX >= 5.1 (for older releases use trace daemon, man trace) Debugger: dbx - * Hex editor: hexedit - * Compiler: XL C/C++ Compiler v8.0 - AIX >= 5.1 ------------------------------------------------------------------------------- Patch XL C/C++ on AIX to bypass expired license restriction ------------------------------------------------------------------------------- Let's begin running truss on the compiler and analysing the output: # truss -f cc -o hallo hallo.c truss output: execve("/usr/vac/bin/cc", 0x2FF223AC, 0x2FF223C0) argc: 4 sbrk(0x00000000) = 0x200043B4 sbrk(0x0000000C) = 0x200043B4 __libc_sbrk(0x00000000) = 0x200043C0 getuidx(4) = 0 ... __loadx(0x0A040000, ... 0x0000D0B2, 0x00000000) = 0x00000000 __loadx(0x0A040000, ... 0x0000D0B2, 0x00000000) = 0x00000000 loadquery(2, 0x20011058, 0x00001000) = 0 __loadx(0x02000200, ... 0xF0D8E580, 0x00000000) = 0x00000000 __loadx(0x07000000, ... 0xF0D8E580, 0x00000000) = 0xF0D8E594 The license for the Evaluation version of kwrite(2, " T h e l i c e n s e".., 43) = 43 IBM XL C/C++ Enterprise Edition V8.0 for AIX kwrite(2, " I B M X L C / C + +".., 44) = 44 Compiler product has expired. kwrite(2, " C o m p i l e r p r".., 31) = 31 kfcntl(1, F_GETFL, 0x00000000) = 67108865 kfcntl(2, F_GETFL, 0x00000000) = 67108865 _exit(1) Start dbx with /usr/vac/bin/cc (or whatever "which cc" returns). truss just displays actual "system calls" as opposed to "library calls" (man truss) so we concentrate on what happens between these two system calls: __loadx(0x07000000, ... 0xF0D8E580, 0x00000000) = 0xF0D8E594 and kwrite(2, " T h e l i c e n s e".., 43) = 43 Why? Well, __loadx is a good starting point to get close enough to the point a call is made to kwrite. From truss' output you can count how many stops you need to get to the desired __loadx call (the one before the kwrite). dbx output: # dbx `which cc` Type 'help' for help. reading symbolic information ...warning: no source compiled with -g (dbx) stop in __loadx [1] stop in __loadx ... (we need exactly 28 stops to get to the desired __loadx) (dbx) cont [1] stopped in glink.__loadx [/usr/lib/libc.a] at 0xd034cdf0 0xd034cdf0 (__loadx) 818208e8 lwz r12,0x8e8(r2) (dbx) cont [1] stopped in glink.__loadx [/usr/lib/libc.a] at 0xd034cdf0 0xd034cdf0 (__loadx) 818208e8 lwz r12,0x8e8(r2) Ok, here we are, the next stop is kwrite so just trace execution until we hit kwrite: (dbx) stop in kwrite [3] stop in kwrite (dbx) tracei [8] tracei (dbx) cont tracei: 0xd034cdf4 (__loadx+0x4) 90410014 stw r2,0x14(r1) tracei: 0xd034cdf8 (__loadx+0x8) 800c0000 lwz r0,0x0(r12) tracei: 0xd034cdfc (__loadx+0xc) 804c0004 lwz r2,0x4(r12) tracei: 0xd034ce00 (__loadx+0x10) 7c0903a6 mtctr r0 tracei: 0xd034ce04 (__loadx+0x14) 4e800420 bctr tracei: 0xd03e695c (dlsym+0x198) 80410014 lwz r2,0x14(r1) tracei: 0xd03e6960 (dlsym+0x19c) 607f0000 ori r31,r3,0x0 ... tracei: 0x10013430 (???) 90610048 stw r3,0x48(r1) tracei: 0x10013434 (???) 80830000 lwz r4,0x0(r3) tracei: 0x10013438 (???) 2c040001 cmpi cr0,0x0,r4,0x1 tracei: 0x1001343c (???) 40820024 bne 0x10013460 (???) tracei: 0x10013440 (???) 8063000c lwz r3,0xc(r3) tracei: 0x10013444 (???) 80810464 lwz r4,0x464(r1) tracei: 0x10013448 (???) 7c032040 cmpl cr0,0x0,r3,r4 tracei: 0x1001344c (???) 41820010 beq 0x1001345c (???) tracei: 0x1001345c (???) 48000008 b 0x10013464 (???) tracei: 0x10013464 (???) 38610050 addi r3,0x50(r1) tracei: 0x10013468 (???) 480001c9 bl 0x10013630 (???) tracei: 0x10013630 (???) 8182015c lwz r12,0x15c(r2) tracei: 0x10013634 (???) 90410014 stw r2,0x14(r1) tracei: 0x10013638 (???) 800c0000 lwz r0,0x0(r12) tracei: 0x1001363c (???) 804c0004 lwz r2,0x4(r12) tracei: 0x10013640 (???) 7c0903a6 mtctr r0 tracei: 0x10013644 (???) 4e800420 bctr tracei: 0xd035ccc8 (time) 38803608 li r4,0x3608 tracei: 0xd035cccc (time+0x4) 93e1fffc stw r31,-4(r1) tracei: 0xd035ccd0 (time+0x8) 7c0802a6 mflr r0 tracei: 0xd035ccd4 (time+0xc) 607f0000 ori r31,r3,0x0 tracei: 0xd035ccd8 (time+0x10) 80a206a4 lwz r5,0x6a4(r2) tracei: 0xd035ccdc (time+0x14) 90010008 stw r0,0x8(r1) ... time library call ... tracei: 0xd035cd70 (time+0xa8) 907f0000 stw r3,0x0(r31) tracei: 0xd035cd74 (time+0xac) 81810058 lwz r12,0x58(r1) tracei: 0xd035cd78 (time+0xb0) 38210050 addi r1,0x50(r1) tracei: 0xd035cd7c (time+0xb4) 83e1fffc lwz r31,-4(r1) tracei: 0xd035cd80 (time+0xb8) 7d8803a6 mtlr r12 tracei: 0xd035cd84 (time+0xbc) 4e800020 blr tracei: 0x1001346c (???) 80410014 lwz r2,0x14(r1) tracei: 0x10013470 (???) 90610050 stw r3,0x50(r1) tracei: 0x10013474 (???) 80810048 lwz r4,0x48(r1) tracei: 0x10013478 (???) 80840010 lwz r4,0x10(r4) tracei: 0x1001347c (???) 7c641810 subfc r3,r4,r3 tracei: 0x10013480 (???) 3c80004f lis r4,0x4f tracei: 0x10013484 (???) 38841a00 addi r4,0x1a00(r4) tracei: 0x10013488 (???) 7c032040 cmpl cr0,0x0,r3,r4 tracei: 0x1001348c (???) 40810068 ble 0x100134f4 (???) tracei: 0x10013490 (???) 80610464 lwz r3,0x464(r1) tracei: 0x10013494 (???) 28032401 cmpli cr0,0x0,r3,0x2401 tracei: 0x10013498 (???) 4182000c beq 0x100134a4 (???) tracei: 0x100134a4 (???) 80620088 lwz r3,0x88(r2) tracei: 0x100134a8 (???) 80a20160 lwz r5,0x160(r2) tracei: 0x100134ac (???) 38630040 addi r3,0x40(r3) tracei: 0x100134b0 (???) 389f00c4 addi r4,0xc4(r31) tracei: 0x100134b4 (???) 4bfff625 bl 0x10012ad8 (???) tracei: 0x10012ad8 (???) 818200ac lwz r12,0xac(r2) tracei: 0x10012adc (???) 90410014 stw r2,0x14(r1) tracei: 0x10012ae0 (???) 800c0000 lwz r0,0x0(r12) tracei: 0x10012ae4 (???) 804c0004 lwz r2,0x4(r12) tracei: 0x10012ae8 (???) 7c0903a6 mtctr r0 tracei: 0x10012aec (???) 4e800420 bctr tracei: 0xd0325f04 (fprintf) 93e1fffc stw r31,-4(r1) tracei: 0xd0325f08 (fprintf+0x4) 607f0000 ori r31,r3,0x0 ... tracei: 0xd0337e8c (write+0x10) 93c1fff8 stw r30,-8(r1) tracei: 0xd0337e90 (write+0x14) 609e0000 ori r30,r4,0x0 tracei: 0xd0337e94 (write+0x18) 93a1fff4 stw r29,-12(r1) tracei: 0xd0337e98 (write+0x1c) 90010008 stw r0,0x8(r1) tracei: 0xd0337e9c (write+0x20) 3806f000 addi r0,-4096(r6) tracei: 0xd0337ea0 (write+0x24) 7c050040 cmpl cr0,0x0,r5,r0 tracei: 0xd0337ea4 (write+0x28) 9381fff0 stw r28,-16(r1) tracei: 0xd0337ea8 (write+0x2c) 9421ff20 stwu r1,-224(r1) tracei: 0xd0337eac (write+0x30) 906100c4 stw r3,0xc4(r1) tracei: 0xd0337eb0 (write+0x34) 408100fc ble 0xd0337fac (write+0x130) tracei: 0xd0337fac (write+0x130) 48000209 bl 0xd03381b4 (kwrite) [3] stopped in kwrite at 0xd03381b4 0xd03381b4 (kwrite) 81820828 lwz r12,0x828(r2) (dbx) The interesting part is the call to the time "library call", and thats also why this call does not appear in the truss output, because it's a "library call". Let's take a closer look at the time libcall and what the AIX ABI says about procedure calls: #include time_t time(Tp) time_t *Tp; time_t is int, long or long int. Just forget about long int because it's only for linux compatibility mode. Depending on the compilation mode, 32 or 64, time_t is int or long, respectively. In AIX ABI there are defined the following conventions for register usage: r3-r10 : procedure arguments r3,r4 : return values r1 : stack pointer r2 : TOC pointer r12 : For glink code Since we are interested in what the caller function does before and after the time libcall, the procedure calling convention gets reduced to: Prologue: 1. Push/Store arguments and/or volatile registers 2. Jump and link ... Epilogue: 1. Restore volatile registers saved previously 2. Use result in r3, r4 For our time libcall it is: Prologue: 1. tracei: 0x10013440 (???) 8063000c lwz r3,0xc(r3) ... tracei: 0x10013464 (???) 38610050 addi r3,0x50(r1) 2. tracei: 0x10013638 (???) 800c0000 lwz r0,0x0(r12) tracei: 0x1001363c (???) 804c0004 lwz r2,0x4(r12) tracei: 0x10013640 (???) 7c0903a6 mtctr r0 tracei: 0x10013644 (???) 4e800420 bctr ... Epilogue: 1. tracei: 0x1001346c (???) 80410014 lwz r2,0x14(r1) ... tracei: 0x10013474 (???) 80810048 lwz r4,0x48(r1) tracei: 0x10013478 (???) 80840010 lwz r4,0x10(r4) 2. tracei: 0x1001347c (???) 7c641810 subfc r3,r4,r3 ... tracei: 0x10013488 (???) 7c032040 cmpl cr0,0x0,r3,r4 tracei: 0x1001348c (???) 40810068 ble 0x100134f4 (???) After time() returns we see a comparison between r3 and r4: cmpl cr0,0x0,r3,r4 and a jump: ble 0x100134f4 (???) Both instructions would read as: "If contents of r3 < than contents of r4 then branch to 0x100134f4 Else continue with next instruction". Common sense tells us this is the inflex point, that is, these two instructions are the difference between normal execution and failure (expiration message). To verify this just try out both options: Take the branch and continue execution. To take the branch, start over again in a new dbx session as seen above and stop at the branch, modify target and continue execution: # ls hallo* hallo.c # dbx `which cc` Type 'help' for help. reading symbolic information ...warning: no source compiled with -g (dbx) stopi at 0x1001348c [1] stopi at 0x1001348c (???) (dbx) run -o hallo hallo.c [1] stopped in . at 0x1001348c 0x1001348c (???) 40810068 ble 0x100134f4 (???) (dbx) gotoi 0x100134f4 <-- goto address as if branch had been taken stopped in . at 0x100134f4 0x100134f4 (???) 48000064 b 0x10013558 (???) (dbx) cont execution completed (dbx) q # ls hallo* hallo hallo.c # ./hallo Hallo Welt! # Nice! This demonstrates we were right with the above assumption. Now on to the next task. We know where to jump to but not where to jump from. The immediate possibility is to modify the ble instruction to jump to the correct address by modifying its offset. That works, ok. But consider that everytime you run the compiler a useless time libcall will be executed. Lets take a closer look on the part before the call to time: ... tracei: 0x10013430 (???) 90610048 stw r3,0x48(r1) tracei: 0x10013434 (???) 80830000 lwz r4,0x0(r3) tracei: 0x10013438 (???) 2c040001 cmpi cr0,0x0,r4,0x1 tracei: 0x1001343c (???) 40820024 bne 0x10013460 (???) tracei: 0x10013440 (???) 8063000c lwz r3,0xc(r3) tracei: 0x10013444 (???) 80810464 lwz r4,0x464(r1) tracei: 0x10013448 (???) 7c032040 cmpl cr0,0x0,r3,r4 tracei: 0x1001344c (???) 41820010 beq 0x1001345c (???) tracei: 0x1001345c (???) 48000008 b 0x10013464 (???) tracei: 0x10013464 (???) 38610050 addi r3,0x50(r1) tracei: 0x10013468 (???) 480001c9 bl 0x10013630 (???) tracei: 0x10013630 (???) 8182015c lwz r12,0x15c(r2) tracei: 0x10013634 (???) 90410014 stw r2,0x14(r1) tracei: 0x10013638 (???) 800c0000 lwz r0,0x0(r12) tracei: 0x1001363c (???) 804c0004 lwz r2,0x4(r12) tracei: 0x10013640 (???) 7c0903a6 mtctr r0 tracei: 0x10013644 (???) 4e800420 bctr tracei: 0xd035ccc8 (time) 38803608 li r4,0x3608 tracei: 0xd035cccc (time+0x4) 93e1fffc stw r31,-4(r1) tracei: 0xd035ccd0 (time+0x8) 7c0802a6 mflr r0 tracei: 0xd035ccd4 (time+0xc) 607f0000 ori r31,r3,0x0 tracei: 0xd035ccd8 (time+0x10) 80a206a4 lwz r5,0x6a4(r2) tracei: 0xd035ccdc (time+0x14) 90010008 stw r0,0x8(r1) ... The branch instructions available in this short section are: tracei: 0x1001343c (???) 40820024 bne 0x10013460 (???) tracei: 0x1001344c (???) 41820010 beq 0x1001345c (???) tracei: 0x1001345c (???) 48000008 b 0x10013464 (???) tracei: 0x10013468 (???) 480001c9 bl 0x10013630 (???) tracei: 0x10013644 (???) 4e800420 bctr We could use any one of those instructions to jump to our offset. Why? Well, thats because if you look at the excerpt, everything that executes is related to the time libcall, registers r3, r4, r12, r0, r1 and r2 (arguments or temporary registers used as pointers). Which one is best? Whenever you have this question go after the unconditional jumps, in this case: tracei: 0x1001345c (???) 48000008 b 0x10013464 (???) The unconditional jump stores the offset to jump to en its low bits. At least when you are not using the Link Register, which is the case (consult AIX assembly reference). Therefore, just put in the offset needed to jump from address 0x1001345c: tracei: 0x1001345c (???) 48000008 b 0x10013464 (???) to the address given in the ble instruction, 0x100134f4: 0x1001348c (???) 40810068 ble 0x100134f4 (???) 0x100134f4 - 0x1001345c = 0x00000098 The new branch is: tracei: 0x1001345c (???) 48000098 b 0x100134f4 (???) Compare both branches, before and after the change, respectively: tracei: 0x1001345c (???) 48000008 b 0x10013464 (???) tracei: 0x1001345c (???) 48000098 b 0x100134f4 (???) With an hexadecimal editor change 48000008 at 0x1001345c to 48000098. # cc -o hallo hallo.c # dbx output: (dbx) stopi at 0x1001345c [1] stopi at 0x1001345c (???) (dbx) run -o hallo hallo.c [1] stopped in . at 0x1001345c 0x1001345c (???) 48000098 b 0x100134f4 (???) (dbx) tracei [3] tracei (dbx) cont tracei: 0x100134f4 (???) 48000064 b 0x10013558 (???) tracei: 0x10013558 (???) 800130a8 lwz r0,0x30a8(r1) tracei: 0x1001355c (???) 7c0803a6 mtlr r0 tracei: 0x10013560 (???) 382130a0 addi r1,0x30a0(r1) tracei: 0x10013564 (???) 83e1fffc lwz r31,-4(r1) tracei: 0x10013568 (???) 4e800020 blr tracei: 0x10003ee8 (???) 60000000 ori r0,r0,0x0 tracei: 0x10003eec (???) 80790128 lwz r3,0x128(r25) tracei: 0x10003ef0 (???) 2c030000 cmpi cr0,0x0,r3,0x0 tracei: 0x10003ef4 (???) 418200d0 beq 0x10003fc4 (???) tracei: 0x10003ef8 (???) 801a0000 lwz r0,0x0(r26) tracei: 0x10003efc (???) 2c000000 cmpi cr0,0x0,r0,0x0 tracei: 0x10003f00 (???) 418000c4 blt 0x10003fc4 (???) tracei: 0x10003f04 (???) 4800e87d bl 0x10012780 (???) tracei: 0x10012780 (???) 81820054 lwz r12,0x54(r2) tracei: 0x10012784 (???) 90410014 stw r2,0x14(r1) tracei: 0x10012788 (???) 800c0000 lwz r0,0x0(r12) tracei: 0x1001278c (???) 804c0004 lwz r2,0x4(r12) tracei: 0x10012790 (???) 7c0903a6 mtctr r0 tracei: 0x10012794 (???) 4e800420 bctr tracei: 0xd031a080 (strlen) 816206a4 lwz r11,0x6a4(r2) tracei: 0xd031a084 (strlen+0x4) 818b0004 lwz r12,0x4(r11) ... Next is the listing of a program coded in C that patches the compiler binary automatically. It also has an option to reverse the patch. Try ./xlcpatch -h gives more info. <++> xlcpatch.c.uue begin 644 xlcpatch.c M"@HC:6YC;'5D92`\2YH/@HC:6YC M;'5D92`\=6YI&ET*&-H87(@*F%R9RD*>PH)<&5R&ET M*"TQ*3L*?0H*=F]I9"!P97)R;W)?8VQO&ET*'9O:60I"GL*"7!R:6YT9B@B57-A M9V4Z7'1X;&-P871C:"!;+7)=(%MF:6QE72`[9FEL92!M=7-T(&)E(&9Q9FX@ M;V8@8V,L(&-C7W(L('AL8RP@971C+EQN("`@("`@7'0@("`@("`@("`@("`@ M("`@("`@("`[9&5F875L=',@=&\@+W5S&ET*"D["@D)96QS92!I9B`H;65M8VUP M*&%R9W9;,5TL("(MPH)"0ER979EPH)"0ER979E M#`P,#$S-#5C M+"!3145+7U-%5"D["@H):68@*"AR970@/"`P>#`P,#$S-#5C*2!\?"`H71E#0X M7'@P,%QX,#!<>#`X(BP@-"D@(3T@,"D*"0D):68@*&UE;6-M<"@H=F]I9"`J M*2!B#0X7'@P,%QX,#!<>#DX(BP@ M-"D@(3T@,"D*"0D)"7!EPH)"0H)"6EF("AM M96UC;7`H*'9O:60@*BD@8G)A;F-H+"`H8V]N#`P7'@Y."(L(#0I("$](#`I"@D)"6EF("AM96UC;7`H*'9O:60@*BD@ M8G)A;F-H+"`H8V]N#`P7'@P."(L(#0I M("$](#`I"@D)"0EP97)R;W)?8VQO65T(BD["@H) M"6)R86YC:%LS72`]("=<>#`X)SL*"@E]"@H)+RH@5W)I=&4@8F%C:R`J+PH* M"7)E="`](#`["@ER970@/2!L#`P,#$S-#5C*2!\?"`H