=-[ http://www.badchecksum.net ]-============================================ =-[ cxxpatch ]-===================================================-[ 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. * 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/13/07 LANGUAGE: English OS: Tru64 VERSION: V5.1B-4 HARDWARE: Alpha ------------------------------------------------------------------------------- BEFORE WE BEGIN ------------------------------------------------------------------------------- Symptom: # cxx -o hello hello.cpp ERROR: This application will not run successfully unless it is used on the processor(s) on which it is licensed. The licensed processor(s) is the one(s) on which the product requiring the CXXOSF PAK will execute. A CXXOSF PAK must be registered in the License Database and activated in the kernel cache before this application will run. Refer to the installation guide for the product requiring the CXXOSF PAK for license database PAK registration instructions. # As stated, a valid CXXOSF PAK is required for this compiler to run. Let's see if we can bypass this restriction somehow, using tracers, debuggers and a hexeditor. Before we start make sure you have the following software already installed. Depending on your OS version you'll need: Tracer: truss - Tru64 V5.1[AB] trace - Tru64 < V5.1 Debugger: dbx, ladebug - * Hex editor: hexedit - * C++ compiler for Tru64: Compaq C++ Compiler 6.5 - Tru64 V5.1[AB] ------------------------------------------------------------------------------- 1. Patch cxx on Tru64 to run without license PAK ------------------------------------------------------------------------------- First of all, run the compiler through a system call tracer, for example, truss: # truss cxx -o hello hello.cpp execve("/bin/cxx", 0x000000011FFFC020, 0x000000011FFFC048) argc = 4 getpagesize() = 8192 brk(0x140313E0) = 0 uname(0x11FFBF40) = 0 getsysinfo(62, 0x11FFBEC0, 128, 0x00000000, 0x00000000, 0x0000302E) = 1 open("/usr/lib/cmplrs/cxx/V6.5-042/comp.config", O_RDONLY, 0666) Err#2 No such file or directory brk(0x1403F3E0) = 0 fork() = 1189 sigaction(SIGINT, 0x11FFBC00, 0x11FFBBE8) = 0 sigaction(SIGTERM, 0x11FFBC00, 0x11FFBBE8) = 0 ERROR: This application will not run successfully unless it is used on the processor(s) on which it is licensed. The licensed processor(s) is the one(s) on which the product requiring the CXXOSF PAK will execute. A CXXOSF PAK must be registered in the License Database and activated in the kernel cache before this application will run. Refer to the installation guide for the product requiring the CXXOSF PAK for license database PAK registration instructions. Received signal #20, SIGCLD [default] siginfo: SIGCLD CLD_EXITED pid=1189 uid=1 status=0x0001 wait4(-1, 0x11FFBC08, 0, 0x11FFBC98) = 1189 sigaction(SIGINT, 0x11FFBC00, 0x11FFBBE8) = 0 sigaction(SIGTERM, 0x11FFBC00, 0x11FFBBE8) = 0 unlink("hello.o") Err#2 No such file or directory unlink("hello.o") Err#2 No such file or directory close(0) = 0 close(1) = 0 close(2) = 0 sigprocmask(SIG_BLOCK, 0xFFFFF137, 0x00000000) = 0 _exit(1) # uhmmm, we got the message, but where is the "write" system call which displays that message? Right above the message we have a fork and after the message we can see a wait4 syscall. Chances are the message is displayed in a forked child, this could be the answer to "where is the write syscall". Run truss again but this time following forks (flag -f for truss): # truss -f cxx -o hello hello.cpp 1195: execve("/bin/cxx", ..., 0x000000011FFFC050) argc = 4 1195: getpagesize() = 8192 1195: brk(0x140313E0) = 0 1195: uname(0x11FFBF40) = 0 1195: getsysinfo(62, ..., 128, ..., ..., 0x0000302E) = 1 1195: open(".../comp.config", O_RDONLY, 0666) Err#2 No such file or directory 1195: brk(0x1403F3E0) = 0 1195: fork() = 1196 1196: fork() (returning as child ...) = 1196 1195: sigaction(SIGINT, 0x11FFBC00, 0x11FFBBE8) = 0 1195: sigaction(SIGTERM, 0x11FFBC00, 0x11FFBBE8) = 0 1196: execve("/usr/lib/cmplrs/cxx/V6.5-042/exx", ..., ...) argc = 18 1196: getpagesize() = 8192 1196: brk(0x1448FF80) = 0 1196: sigaction(SIGBUS, 0x11FFBDE0, 0x11FFBDC8) = 0 1196: sigaction(SIGSEGV, 0x11FFBDE0, 0x11FFBDC8) = 0 1196: gettimeofday(0x11FFBDB0, 0x00000000) = 0 1196: getrusage(RUSAGE_SELF, 0x11FFBD40) 1196: getrusage(RUSAGE_SELF, 0x11FFBD00) = 0 1196: getrusage(RUSAGE_CHILDREN, 0x11FFBD00) = 0 1196: gettimeofday(0x11FFBCF0, 0x00000000) = 0 1196: table(TBL_TTYLOC, 301972656, 0x00000001, 64, 64) = 1 1196: brk(0x144A0000) = 0 1196: ioctl(1, TIOCGETP, 0x11FFB8F8) = 0 1196: ioctl(1, TIOCGWINSZ, 0x11FFB908) = 0 1196: ioctl(2, TIOCGETP, 0x11FFB8F8) = 0 1196: ioctl(2, TIOCGWINSZ, 0x11FFB908) = 0 1196: setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) Err#2 No such file or directory 1196: setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) Err#2 No such file or directory 1196: setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) Err#2 No such file or directory 1196: setsysinfo(7, 0x11FFBC00, 160, 0x00000000, 4) Err#2 No such file or directory ERROR: This application will not run successfully unless it is used on the processor(s) on which it is licensed. The licensed processor(s) is the one(s) on which the product requiring the CXXOSF PAK will execute. A CXXOSF PAK must be registered in the License Database and activated in the kernel cache before this application will run. Refer to the installation guide for the product requiring the CXXOSF PAK for license database PAK registration instructions. 1196: write(2, " E R R O R : T h i s ".., 462) = 462 1196: close(0) = 0 1196: close(1) = 0 1196: close(2) = 0 1196: sigprocmask(SIG_BLOCK, 0xFFFFF137, 0x00000000) = 0 1196: _exit(1) 1195: Received signal #20, SIGCLD [default] 1195: siginfo: SIGCLD CLD_EXITED pid=1196 uid=1 status=0x0001 1195: wait4(-1, 0x11FFBC08, 0, 0x11FFBC98) = 1196 1195: sigaction(SIGINT, 0x11FFBC00, 0x11FFBBE8) = 0 1195: sigaction(SIGTERM, 0x11FFBC00, 0x11FFBBE8) = 0 1195: unlink("hello.o") Err#2 No such file or directory 1195: unlink("hello.o") Err#2 No such file or directory 1195: close(0) = 0 1195: close(1) = 0 1195: close(2) = 0 1195: sigprocmask(SIG_BLOCK, 0xFFFFF137, 0x00000000) = 0 1195: _exit(1) # Superb, we found the write syscall: 1196: write(2, " E R R O R : T h i s ".., 462) = 462 Trace the fork: 1195: fork() = 1196 1196: fork() (returning as child ...) = 1196 1195: sigaction(SIGINT, 0x11FFBC00, 0x11FFBBE8) = 0 1195: sigaction(SIGTERM, 0x11FFBC00, 0x11FFBBE8) = 0 1196: execve("/usr/lib/cmplrs/cxx/V6.5-042/exx", ..., ...) argc = 18 So we have two processes, the parent (pid 1195) and the child (pid 1196). Furthermore, the child's image is /usr/lib/cmplrs/cxx/V6.5-042/exx. Since the message is written in the child, we concentrate on /usr/lib/cmplrs/cxx/V6.5-042/exx. erm, BTW, anyone noticed the child fork line: 1196: fork() (returning as child ...) = 1196 fork() returning the child pid in the child process? Weird... :S (refer to man fork) Back to the important things. Now trace from the fork to the write (or backtrace from write to fork), the code that checks for a valid license PAK must be in this range: 1195: fork() = 1196 1196: fork() (returning as child ...) = 1196 ... 1196: execve("/usr/lib/cmplrs/cxx/V6.5-042/exx", 0x14024C00, 0x1402AD00) argc = 18 ... 1196: ioctl(2, TIOCGWINSZ, 0x11FFB908) = 0 1196: setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) Err#2 No such file or directory 1196: setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) Err#2 No such file or directory 1196: setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) Err#2 No such file or directory 1196: setsysinfo(7, 0x11FFBC00, 160, 0x00000000, 4) Err#2 No such file or directory irectory ERROR: This application will not run successfully unless it is used on the processor(s) on which it is licensed. The licensed processor(s) is the one(s) on which the product requiring the CXXOSF PAK will execute. A CXXOSF PAK must be registered in the License Database and activated in the kernel cache before this application will run. Refer to the installation guide for the product requiring the CXXOSF PAK for license database PAK registration instructions. 1196: write(2, " E R R O R : T h i s ".., 462) = 462 ... The interesting part here is the setsysinfo syscall. What does this call actually do? man setsysinfo: NAME setsysinfo - Set system information SYNOPSIS #include #include setsysinfo(op, buffer, nbytes, arg, flag) unsigned long op; datatype *buffer; unsigned long nbytes; datatype *arg; unsigned long flag; DESCRIPTION The setsysinfo system call modifies system information. Compare the prototype to our actual syscall and relate arguments: setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) op = 7 buffer = 0x11FFBC10 nbytes = 160 arg = NULL flag = 4 As described in the manual, op is a field that determines the operation to be performed. We have a 7, let's look in the headers (sys/sysinfo.h and machine/hal_sysinfo.h) for setsysinfo operations: # vi /usr/include/sys/sysinfo.h ... 476 /* 477 * setsysinfo() operation types 478 */ 479 480 #define SSI_NVPAIRS 1 481 482 483 #define SSI_ZERO_STRUCT 2 484 485 #define SSI_SET_STRUCT 3 486 487 ... 491 492 #define SSI_LMF 7 493 494 #define SSI_LOGIN 8 495 /* (Sets SLOGIN flag in proc struct) */ ... # 1, 2, 3, ... oh, a 7. uhmmm, this looks good: SSI_LMF. setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) setsysinfo(SSI_LMF, 0x11FFBC10, 160, 0x00000000, 4) The second arg is: datatype *buffer; As described in manual, it's the buffer stored in userspace containing the system information! Our buffer is at address 0x11FFBC10. Third arg: unsigned long nbytes; Just the length of the buffer. Forth and fifth arg: datatype *arg; unsigned long flag; man setsysinfo: arg, flag The arg and flag arguments can be used by certain op values to store information. When the flag argument or both the arg and flag arguments are not required for a given op, they should be set to NULL. In our case, arg is NULL but flag isn't. As you read the setsysinfo manual it gets clear that both arg and/or flag give finer grained control over the operation to be performed. The problem is we neither have defined the operation 7 for setsysinfo (undocumented SSI_LMF) nor do we know what a flag 4 does with operation SSI_LMF. There are a couple of options on how to proceed from here. Try to obtain more information about setsysinfo and what this 160 byte buffer is all about or use a debugger to trace execution from start of program to the setsysinfo syscall. We will take both approaches: ------------------------------------------------------------------------------- 1.1 Gathering more information about setsysinfo ------------------------------------------------------------------------------- Let's get back to the manual page for setsysinfo 'man setsysinfo'. You should always, if not already do so, take a look at the 'SEE ALSO' section of the man pages. That's because there might be references to related commands, functions, etc. that could be very, very helpful: # man setsysinfo ... SEE ALSO Commands: iec(1), uac(1) Functions: getsysinfo(2) Files: signal(4) # getsysinfo(2), uhmmm. Sounds like the "counterpart" of setsysinfo, doesn't it? # man getsysinfo ... GSI_LMF Returns LMF (License Management Facility) kernel information. LMF definitions are in the and header files. You must specify an arg parameter. The other parameter values vary depending on what you specify for arg. See the LMF header files to determine which input parameters are required. ... # We just found a new way to walk along. Think about it, the prototype for this function is: getsysinfo (op, buffer, nbytes, start, arg, flag) unsigned long op; caddr_t buffer; unsigned long nbytes; int *start; void *arg; unsigned long *flag; Where: buffer Specifies the location where the system information is returned. Its data type depends upon the operation you specify. nbytes Defines the size of buffer. As could be deduced from the setsysinfo man page and output from trace, the buffer contains information specific for the operation to be performed. Since we are setting information about a license (SSI_LMF), the buffer should contain some structure describing a license. Now in man getsysinfo we have found two new headers that deal with lmf related stuff: # vi /usr/include/sys/lmfklic.h ... /* Values for flag argument to getsysinfo */ #define LMF_GETSERV 1 #define LMF_GETSMM 2 #define LMF_GETLIC 3 /* Values for flag argument to setsysinfo */ #define LMF_SETSERV 1 #define LMF_SETLIC 2 #define LMF_ADJLIC 3 #define LMF_GETAUTH 4 #define LMF_RELAUTH 5 #define LMF_SETSMM 6 ... typedef struct lmf_klicense { struct lmf_klicense *kl_next; time_t kl_release_date; time_t kl_termination; ver_t kl_version; int kl_act_charge; int kl_locked_units; ... char kl_product_name[LMF_PRODUCT]; char kl_producer[LMF_PRODUCER]; char kl_product_token[LMF_TOKEN]; char kl_hardware_id[LMF_HARDWARE]; } klic_t; # Here are the flags for setsysinfo, finally! And now we also know that licenses in the kernel are described using the klic_t structure. Our setsysinfo call turns out to be: setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) #define SSI_LMF 7 /* /usr/include/sys/sysinfo.h */ | | V setsysinfo(SSI_LMF, 0x11FFBC10, 160, 0, 4) #define LMF_GETAUTH 4 /* /usr/include/sys/lmfklic.h */ | | V setsysinfo(SSI_LMF, 0x11FFBC10, 160, 0, LMF_GETAUTH) Thats what we got so far. Let's shed some light over the buffer's content. The setsyscall is trying to verify if we have a valid CXXOSF license enabled and active in the kernel cache. Therefore, the buffer is *most probably* the kernel license structure described in /usr/include/sys/lmfklic.h. We could code our own setsysinfo call and run it, both with a valid license (enabled and active) and with an invalid one (CXXOSF, for example). Compile the following program: <++> test1.c.uue begin 644 test1.c M"B-I;F-L=61E(#QS=&1I;RYH/@HC:6YC;'5D92`\&ET*"D*>PH)<')I M;G1F*")5PH*"6EF("AA&ET*")-14U#4%D@4%)/1%5#5"(I.PH*"@EI9B`H;65M8W!Y*"AV M;VED("HI("9K;&EC+FML7W!R;V1U8V5R+"`H=F]I9"`J*2!A exxdis # grep -E 'lda.*v0, 257\(zero\)' exxdis 0x127c7740: 201f0101 lda v0, 257(zero) # Normally all syscall codes are loadedi into v0 using the "lda" instruction and 257 is the syscall code for setsysinfo (/usr/include/sys/syscall.h). To be sure this is the setsysinfo syscall just look at the next instruction to see if there is a call_pal: 0x127c773c: 2ffe0000 ldq_u zero, 0(sp) 0x127c7740: 201f0101 lda v0, 257(zero) 0x127c7744: 00000083 call_pal callsys 0x127c7748: e6600005 beq a3, 0x127c7760 0x127c774c: c3a00000 br gp, 0x127c7750 call_pal callsys actually does the call, so we can be sure this is the setsysinfo syscall - Using findsc.pl (given in *.uue format below) # perl findsc.pl /usr/lib/cmplrs/cxx/V6.5-042/exx tsize 7e0000 entry 1215b4c0 text_start 12000000 Offset into file 15b4c0 ######## ##### ######### #Offset# #Num# #Syscall# #################### ####### ########################### [0x00000000007aa674] 256 getsysinfo [0x00000000007aaa84] 67 pre_F64_stat [0x00000000007aac54] 33 access [0x00000000007acaa4] 87 gethostname [0x00000000007ad0d4] 142 gethostid [0x00000000007ad3c4] 136 mkdir ... [0x00000000007c7704] 64 getpagesize [0x00000000007c7744] 257 setsysinfo [0x00000000007c81d4] 41 dup ... [0x0000000000853a28] -1 Unknown [0x0000000000853a3c] -1 Unknown [0x0000000000853a50] -1 Unknown # Note the offsets are given as real offsets into the file. To get the virtual address corresponding to that offset just add the text_start. Now that we've got the address, open dbx with /usr/lib/cmplrs/cxx/V6.5-042/exx and set a breakpoint at this address: # dbx /usr/lib/cmplrs/cxx/V6.5-042/exx dbx version 5.1 Type 'help' for help. warning: /usr/lib/cmplrs/cxx/V6.5-042/exx has no symbol table -- very little is supported without it (dbx) stopi at 0x127c7740 [2] stopi at 0x127c7740 (dbx) run [2] stopped at >*[., 0x127c7740] lda v0, 257(zero) (dbx) stepi >*[., 0x127c7748] beq a3, 0x127c7760 (dbx) print $v0 2 (dbx) The return value of setsysinfo is 2, hence truss' output: 1196: setsysinfo(7, 0x11FFBC10, 160, 0x00000000, 4) Err#2 No such file or directory Special attention must be paid to branches since any of them could be the point between correct execution or failure (license message is displayed). The branch immediately following the call_pal instruction branches only if register a3 is zero. a3 is the argument register containing the fourth argument to setsysinfo: a0 = 7 a1 = 0x11FFBC10 a2 = 160 a3 = 0x00000000 a4 = 4 So a3 should be 0x00: (dbx) print $a3 1 1??? It should have been 0, since there was NO instruction between the call and the current instruction that altered register a3. The only possible cause is that register a3 got altered by the setsysinfo call as a side effect. If you follow the execution with dbx using the modified /usr/lib/cmplrs/cxx/V6.5-042/exx of section 1.1 you'll notice that a3 is 0 at this point. What changed? The only difference is successful execution of setsysinfo. Conclusion: When setsysinfo returns an error its side effect is a 1 in register a3, otherwise a3 remains 0 or whatever value it had before the call. With this in mind, change its value to 0 and follow execution: (dbx) assign $a3=0 (dbx) stepi (omitting prompt for clarity) >*[., 0x127c7760] ret zero, (ra), 1 >*[., 0x127a08ac] ldq s0, 8(sp) >*[., 0x127a08b0] ldq s1, 16(sp) >*[., 0x127a08b4] ldah gp, 426(ra) >*[., 0x127a08b8] ldq ra, 0(sp) >*[., 0x127a08bc] lda gp, 9012(gp) >*[., 0x127a08c0] lda sp, 192(sp) >*[., 0x127a08c4] ret zero, (ra), 1 >*[., 0x1215d638] ldah gp, 524(ra) >*[., 0x1215d63c] cmpult s2, 0x3, t0 >*[., 0x1215d640] lda gp, 23384(gp) >*[., 0x1215d644] beq v0, 0x1215d6a0 Here we have another beq that branches if v0 is 0. v0 is NOT altered until now when its value is retrieved for beq. When does v0 contain 0? Answer: When setsysinfo returns 0, that is, when it is successful (it found a valid license). Since our setsysinfo was not successful it is not going to be zero as you've seen above so change its value and continue: (dbx) print $v0 2 (dbx) assign $v0=0 0 (dbx) cont Program terminated normally (dbx) No license message is displayed, this should be the right way. Now lets see how we can modify some instructions to set v0 and a3 to zero and avoid setsysinfo altogether, we don't need it. For example: Before calling setsysinfo (call_pal callsys), set v0 to 0 with the instruction preceding the call_pal, "lda v0, 0(zero)" and change "call_pal callsys" to do something useless, for example NOP, which in Alpha Architecture is accomplished with bis R31, R31, R31 (47ff041f). This would leave a 0 in v0 and a3 would be 0 too and would NOT be altered since setsysinfo is not called. With a hexeditor change these two instructions: 0x127c7740: 201f0101 lda v0, 257(zero) 0x127c7744: 00000083 call_pal callsys to: 0x127c7740: 201f0000 lda v0, 0(zero) 0x127c7744: 47ff041f bis zero, zero, zero a3 is loaded with 0 as before because the fourth arg to setsysinfo is 0. v0 is loaded with 0 instead 257. Check if everything works as expected: # dbx /usr/lib/cmplrs/cxx/V6.5-042/exx dbx version 5.1 Type 'help' for help. warning: /usr/lib/cmplrs/cxx/V6.5-042/exx has no symbol table -- very little is supported without it (dbx) stopi at 0x127c7740 [2] stopi at 0x127c7740 (dbx) r [2] stopped at >*[., 0x127c7740] lda v0, 0(zero) (dbx) p $v0 327680 (dbx) p $a3 0 (dbx) stepi >*[., 0x127c7744] bis zero, zero, zero (dbx) p $v0 0 (dbx) p $a3 0 (dbx) stepi >*[., 0x127c7748] beq a3, 0x127c7760 (dbx) cont Program terminated normally (dbx) q # # cxx -o hello hello.cpp # ./hello Hello World # ------------------------------------------------------------------------------- findsc.pl is a little script that scans executable eCOFF files for common Tru64 syscall patterns and prints the results on screen. Try "perl findsc.pl" without arguments for help. <++> findsc.pl.uue begin 600 findsc.pl M(R$O=7-R+VQO8V%L+V)I;B]P97)L("UW"B,*(R!F:6YD&ET2!B>71E71E71E71E M2`D:&5X7VYU;2`](&IO:6XH)R71EPH)"6AE>"AS=6)S='(H M)&AE>%]N=6TL("1N=6TL("1N=6TI*2`K("AH97@HPH)"6AE>"@D:&5X7VYU M;2D["@E]"GT*"@IS=6(@;G5M7V9O2`H)&YU;2D@/2!` M7SL*"6UY("1P860@/2`B(")X*#<@+2!L96YG=&@H(B1N=6TB*2D["@ER971U M'0@PHC(#`@("`@("`@(&-O9F9?=7-H;W)T("`@ M("!F7VUA9VEC.R`@("`@("`@+RH@;6%G:6,@;G5M8F5R("HO"B,@,B`@("`@ M("`@8V]F9E]U7!E9&5F('-T2HO"B,T,"`@8V]F9E]L;VYG("`@("!D3L@("`@("`@("`@+RH@96YT&5C=71A8FQE(&9I;&4Z("0A(CL*8FEN;6]D92A&2"D[ M"@HC($IU;7`@=&\@='-I>F4@9FEE;&0@:6X@:&5A9&5R(&%N9"!E>'1R86-T M(&ET"FUY("1T"(L("1T'1?'1?5]O9F9S970@/2`D=&5X=%]S=&%R="!>("1E;G1R>3L*<')I;G0@ M(D]F9G-E="!I;G1O(&9I;&4@(B`N('-P'0@F5R M;RP@;BP@=C`@("`@("`@-#-E,#$T,#`@9F]R(&X@/2`P.PHC(&-A;&Q?<&%L M(&-A;&QS>7,@("`@("`@,#`P,#`P.#,*(PH*(R!,;V%D('-Y2`E&ET(BP*,B`]/B`B9F]R:R(L M"C,@/3X@(G)E860B+`HT(#T^(")W&5C M7W=I=&A?;&]A9&5R(BP*,C8@/3X@(G!T2(L"CDW(#T^(")S;V-K970B+`HY."`] M/B`B8V]N;F5C="(L"CDY(#T^(")A8V-E<'0L;VQD7V%C8V5P="(L"C$P,"`] M/B`B9V5T<')I;W)I='DB+`HQ,#$@/3X@(G-E;F0L;VQD7W-E;F0B+`HQ,#(@ M/3X@(G)E8W8L;VQD7W)E8W8B+`HQ,#,@/3X@(G-I9W)E='5R;B(L"C$P-"`] M/B`B8FEN9"(L"C$P-2`]/B`BF5F38T(BP*,C,Q(#T^(")S971T:6UE;V9D87DV-"(L M"C(S,R`]/B`B9V5T<&=I9"(L"C(S-"`]/B`B9V5T7-I;F9O(BP*,C4W(#T^(")S971S>7-I M;F9O(BP*,C4X(#T^(")A9G-?6YC(BP*,C8R(#T^ M(")O9FQO8VLB+`HR-C,@/3X@(E]&-C1?&QA=&4B+`HI.PH*"G!R:6YT(")<;EQN M(CL*<')I;G0@(B,C(R,C(R,C("`@("`@("`@("`@(",C(R,C("`@(R,C(R,C M(R,C7&XB.PIP71E"(L(&=E=$)Y=&5S*"@D;V9FPH)"0D):68@*'-U8G-TPH)"0D)"2,@1&5C;V1E(&EN"AS=6)S='(H)&EN M7-C86QL(#T@(E5N:VYO=VXB.PH)"0D)"7T*"@D)"0E] M"@D)"0EE;'-I9B`H*'-U8G-T7-C86QL(#T@)'-YR1S8U]N=6U].PH)"0D) M"7T*"0D)"0EE;'-E"@D)"0D)>PH)"0D)"0DD"(@+B!S<')I;G1F M*"(E,#$V>"(L("1O9F9S970I("X@(ET@(B`N("9N=6U?9F]R;6%T*"1S8U]N M=6TI("X@(B`D7-C86QL(#T@(B(["@DD8V]U;G0@ +*ST@-#L*?0H*"@IN ` end <--> cxxpatch is a program that patches exx. It has two functional modes: 1. Patch 2. Reverse the patch Try ./cxxpatch -h for help. <++> cxxpatch.c.uue begin 600 cxxpatch.c M"@HC:6YC;'5D92`\7,O='EP97,N:#X*(VEN8VQU9&4@/'5N:7-T9"YH/@HC:6YC;'5D M92`\97)R;F\N:#X*(VEN8VQU9&4@/'-TPH)<')I;G1F*"(N+V-X>'!A=&-H(%LM:')=(%ME M>'A=7&XB*3L*"7!R:6YT9B@B7'0M:#H@1&ES<&QA>2!T:&ES(&AE;'!<;B(I M.PH)<')I;G1F*")<="UR.B!2979E'@Z(&9Q9FX@=&\@97AX(&5X96-U=&%B;&5<;EQN(BD["@H)97AI="@M M,2D["GT*"@IV;VED('-H;W=?97)R;W)?97AI="AI;G0@9F0I"GL*"6EF("AF M9"`A/2`M,2D*"0EC;&]S92AF9"D["@H)<')I;G1F*")%4E)/4CH@)7-<;B(L M('-T&ET*"TR*3L*?0H*:6YT(&UA:6XH:6YT M(&%R9V,L(&-H87(@*F%R9W9;72D*>PH)+RH@1&5F875L="!C;VUP:6QE&5C=71A8FQE("HO"@EC:&%R("ID969?97AX(#T@(B]U'@O5C8N-2TP-#(O97AX(CL*"6-H87(@*FYE=U]E>'@@/2!.54Q,.PH) M:6YT(&9D(#T@+3$["@EU;G-I9VYE9"!C:&%R(')E=F5R"`](&1E9E]E>'@["@EE;'-E(&EF("AA&ET*"D["@D)96QS92!I9B`H M(7-T#L*"0E]"@D)96QS90H)"0EN97=?97AX(#T@87)G=ELQ73L*"@E]"@EE M;'-E(&EF("AA'@L($]?4D17 M4BDI(#T]("TQ*0H)"7-H;W=?97)R;W)?97AI="@M,2D["@H)+RH@2G5M<"!T M;R!S971S>7-I;F9O(&ENF5R;RD@;W(@=FEC979E7,@=&\@3D]0(#T@8FES('IE2!P871C:&5D(BD["@H)