├── LICENSE ├── Makefile ├── README.md ├── doc ├── LICENSE ├── README └── TODO ├── include ├── decompress.h ├── elfuck.h ├── execelf.h ├── getpw.h ├── lock.h ├── nrv2e.h ├── poly.h └── stubify.h └── src ├── Makefile ├── antidump.S ├── decompress.S ├── elfuck.c ├── execelf.S ├── getpw.c ├── lock.S ├── nrv2e.c ├── poly.c └── stubify.c /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ef: src/elfuck 2 | src/elfuck:src/elfuck.c src/getpw.c src/nrv2e.c src/poly.c src/stubify.c src/decompress.S src/execelf.S src/lock.S include/decompress.h include/elfuck.h include/execelf.h include/getpw.h include/lock.h include/nrv2e.h include/poly.h include/stubify.h 3 | (cd src; make elfuck) 4 | clean: 5 | rm -f ef core 6 | (cd src; make clean) 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elfuck 2 | ELF packer for i386 3 | origial version from sk2 by sd 4 | -------------------------------------------------------------------------------- /doc/LICENSE: -------------------------------------------------------------------------------- 1 | ELFuck - ELF ultimate compression kit (c) 2002 by sd 2 | +-----------------------------------------------------------------------+ 3 | This program is free software; you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; either version 2 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program; if not, write to the Free Software 15 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 | -------------------------------------------------------------------------------- /doc/README: -------------------------------------------------------------------------------- 1 | ELFuck - ELF ultimate compression kit 2 | +-----------------------------------+ 3 | ELFuck is basicaly compression utility, now extended by ELF password 4 | locking and string-burning, including polymorphics features to make 5 | pattern detection of protected binaries a bit harder. 6 | 7 | Compression (1-9 level) 8 | +---------------------+ 9 | ELFuck uses excellent Markus F.X.J. Oberhumer's compression algorithm, 10 | NRV2E which carries very good compression with tiny decompressor 11 | (about 128 bytes!). This algorithm family is stolen from UPX, with 12 | difference in that decompression is done in real time; ELFuck will 13 | decompress ELF directly to .text/.data segment and executes authentic 14 | ELF image from there, on other hand, UPX creates original ELF in /tmp 15 | and execve() it, so that we don't need any writeable filesystem at all. 16 | Well, I should place note there that it is braindead to pack binaries 17 | smaller than 1kb, because ELFuck have to add 128 bytes of decompressor 18 | code and about 400 bytes of ELF loader and ELF header. For reference, 19 | table with ratios compared to gzip: 20 | 21 | File Original size NRV2E % gzip 22 | -------------------------------------------------------------- 23 | /bin/bash 512540 245592 (47%) 243346 24 | /etc/termcap 700857 224779 (32%!) 225821 25 | /bin/rpm (static) 1328424 622559 (46%!) 628622 26 | /bin/ls 43740 21537 (49%!) 21569 27 | /boot/vmlinux 1296935 562507 (43%) 558392 28 | 29 | you see, in some cases it's better than gzip (well, compression 30 | takes more time, however) ... 31 | 32 | Locking (-l option) 33 | +-----------------+ 34 | Because ELFuck is 100%-ly based on stolen ideas, I also implemented 35 | this one of BurnEye. Someone may like to disallow other users to 36 | use/analyse your binary (public shells, root browsing user's homes). 37 | The algorithm is kinda simple, but seems to be pretty effective: 38 | We'll select some password; expand it using sha1 to 160 bit key. 39 | by this key we'll encrypt, using RC4 algorithm, whole binary 40 | (except the decrypting stub, of course). We'll also keep 41 | last 32bits of sha1 against original binary, in order to check password. 42 | When someone will execute such protected binary; the stub will ask for 43 | password, make hash of it and try to decrypt the binary back using 44 | this key. Then we'll make a hash of potentially decrypted binary, 45 | check it against the value we've saved while creating, and if matches, 46 | the binary is decrypted correctly (=right password) and we'll let it 47 | run. 48 | 49 | Note, that the locked binary will look for 'EPW' shell variable, in case 50 | is there, password will be taken from it instead. This is useful 51 | when you've a lot of binaries locked with same password, so you'll just 52 | do `export EPW=password`, you'll not be asked for password anymore. 53 | 54 | This kind of protection of binaries is very strong, as someone without 55 | password will need to crack RC4 ... Good luck! 56 | 57 | Polymorphism / string burning (-s option) 58 | +---------------------------------------+ 59 | Well, we're also using virus technology for good purposes ;) 60 | Using this option (-s) you'll get mutated binary each time, 61 | sucessfuly defeating pattern-scanners. However, the polymorphic 62 | decryptor will take about 500 bytes ;( For further details 63 | on polymorphic engine, look at poly.c 64 | 65 | However, to propagate itself, elfuck always put it's banner into 66 | generated ELF's header. To disable this behavior, use -b option. 67 | 68 | ATTENTION! 69 | +--------+ 70 | Backup your target binary before using this utility! The name is not 71 | random, the way we're loading ELF binary into memory is not so clean, 72 | so things are just getting fucked up sometimes ;) 73 | 74 | Have fun! 75 | -sd 76 | -------------------------------------------------------------------------------- /doc/TODO: -------------------------------------------------------------------------------- 1 | + polymorphic ELF header 2 | -------------------------------------------------------------------------------- /include/decompress.h: -------------------------------------------------------------------------------- 1 | #ifndef DECOMPRESS_H 2 | #define DECOMPRESS_H 3 | extern void decompress(void); 4 | extern void decompress_end(void); 5 | extern ulong decompress_src; 6 | extern ulong decompress_dest; 7 | #define DECOMPRESS_SIZE ((unsigned) decompress_end - (unsigned) decompress) 8 | #endif 9 | -------------------------------------------------------------------------------- /include/elfuck.h: -------------------------------------------------------------------------------- 1 | #ifndef ELFUCK_H 2 | #define ELFUCK_H 3 | 4 | #define ELF_BANNER "\nELFuck 0.1 compressed (c) 2002 by sd \n" 5 | #define BANNER "ELFuck 0.1, real-time ELF executables compression/encryption\n" \ 6 | "(c) Copyright 2002 by sd \n" 7 | 8 | #ifndef ulong 9 | #define ulong unsigned long 10 | #endif 11 | #ifndef uchar 12 | #define uchar unsigned char 13 | #endif 14 | #ifndef uint 15 | #define uint unsigned int 16 | #endif 17 | 18 | #define eprintf(fmt...) fprintf(stderr, fmt) 19 | #define ALIGNDOWN(x) ((x)&(~4095)) 20 | #define ALIGNUP(x) ALIGNDOWN((x)+4095) 21 | 22 | #define FLAG_NOBANNER 1 23 | #define FLAG_SCRAMBLE 2 24 | #define FLAG_LOCK 4 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/execelf.h: -------------------------------------------------------------------------------- 1 | #ifndef EXECELF_H 2 | #define EXECELF_H 3 | extern void execelf(void); 4 | extern void execelf_end(void); 5 | extern void e_skip_interp(void); 6 | extern void e_no_interp(void); 7 | extern char execelf_interp[256]; 8 | #define EXECELF_SIZE ((unsigned) execelf_end - (unsigned) execelf) 9 | #endif 10 | -------------------------------------------------------------------------------- /include/getpw.h: -------------------------------------------------------------------------------- 1 | #ifndef GETPW_H 2 | #define GETPW_H 3 | 4 | #ifndef __ASSEMBLY__ 5 | void getpassw(uchar *hash); 6 | #endif 7 | #define MAXPASS 56 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/lock.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCK_H 2 | #define LOCK_H 3 | 4 | extern void elf_lock(); 5 | extern ulong lock_start; 6 | extern ulong lock_testkey; 7 | extern ulong locked_len; 8 | extern void elf_lock_end(); 9 | extern void sha1_asm(uchar *, char *, int); 10 | extern void rc4_asm(uchar *, char *, int); 11 | 12 | #define LOCK_SIZE ((ulong) elf_lock_end - (ulong) elf_lock) 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/nrv2e.h: -------------------------------------------------------------------------------- 1 | /* implementation of the NRV2E-99 compression algorithm */ 2 | #ifndef NRV2E_H 3 | #define NRV2E_H 4 | #include "elfuck.h" 5 | extern int ucl_nrv2e_99_compress(uchar *, uint, uchar *, uint *, void *, int, void *, uint *); 6 | #endif 7 | -------------------------------------------------------------------------------- /include/poly.h: -------------------------------------------------------------------------------- 1 | #ifndef POLY_H 2 | #define POLY_H 3 | 4 | typedef struct { 5 | unsigned long a,b; 6 | unsigned paddr, plen; 7 | unsigned len; 8 | unsigned start; 9 | } poly_key; 10 | 11 | #define MAXGAPLEN 16 12 | #define MINGAPLEN 8 13 | #define MAXJUNK 3 14 | 15 | //#define NOPGAP 16 | 17 | char *poly_gen(poly_key *key); 18 | void poly_encrypt(unsigned char *data, int len, poly_key *key); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/stubify.h: -------------------------------------------------------------------------------- 1 | #ifndef STUBIFY_H 2 | #define STUBIFY_H 3 | #include 4 | extern int pack_elf(char *, char *, int, int); 5 | 6 | typedef struct { 7 | void (*callback) (int, uint, int, void * user); 8 | void *user; 9 | } ucl_callback; 10 | 11 | struct stub { 12 | struct elf32_hdr elf; 13 | struct elf32_phdr phdr; 14 | uchar data[1]; 15 | } __attribute__ ((packed)); 16 | 17 | struct elf_aux { 18 | ulong phdr; 19 | ulong phnum; 20 | ulong entry; 21 | ulong freestart; 22 | ulong freelen; 23 | } __attribute__ ((packed)); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | #CC=dietlibc/diet gcc 2 | CC=gcc 3 | CFLAGS=-Wall -O2 -fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -z execstack -I../include 4 | LDFLAGS=-s 5 | .c.o: 6 | $(CC) $(CFLAGS) -c $< 7 | .S.o: 8 | $(CC) $(CFLAGS) -c $< 9 | elfuck:elfuck.o getpw.o nrv2e.o poly.o stubify.o decompress.o execelf.o lock.o 10 | $(CC) $(CFLAGS) -o elfuck elfuck.o getpw.o nrv2e.o poly.o stubify.o decompress.o execelf.o lock.o 11 | clean: 12 | rm -f *.o elfuck core 13 | elfuck.o: ../include/elfuck.h ../include/stubify.h 14 | getpw.o: ../include/elfuck.h ../include/lock.h ../include/getpw.h 15 | nrv2e.o: 16 | poly.o: ../include/elfuck.h ../include/poly.h 17 | stubify.o: ../include/nrv2e.h ../include/elfuck.h ../include/decompress.h ../include/execelf.h ../include/stubify.h ../include/poly.h ../include/getpw.h ../include/lock.h 18 | ../include/decompress.h: 19 | ../include/elfuck.h: 20 | ../include/execelf.h: 21 | ../include/getpw.h: 22 | ../include/lock.h: 23 | ../include/nrv2e.h: ../include/elfuck.h 24 | ../include/poly.h: 25 | ../include/stubify.h: 26 | -------------------------------------------------------------------------------- /src/antidump.S: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: antidup.S, this makes tracing of binary a bit harder. We're 3 | * achieving this by simple technique -- we're tracing it first, 4 | * linux won't allow ptrace() at one pid twice. 5 | */ 6 | 7 | .globl antidump 8 | .globl antidump_end 9 | 10 | antidump: 11 | xor %eax, %eax 12 | mov $190, %al 13 | int $0x80 14 | test %eax, %eax 15 | jz traced_child 16 | wait_loop: 17 | xor %edx, %edx 18 | push %ecx 19 | or $-1, %ebx 20 | mov %esp, %ecx 21 | push $7 22 | pop %eax 23 | int $0x80 24 | pop %ebx 25 | cmp $0x7f, %bl 26 | mov %bh, %bl 27 | jne go_exit 28 | /* child got signal, deliver it */ 29 | and $63, %ebx 30 | mov %ebx, %esi 31 | xchg %ecx, %eax 32 | push $7 33 | pop %ebx 34 | push $26 35 | pop %eax 36 | int $0x80 37 | jmp wait_loop 38 | go_exit: 39 | push $1 40 | pop %eax 41 | int $0x80 42 | traced_child: 43 | xor %ebx, %ebx 44 | push $26 45 | pop %eax 46 | int $0x80 47 | test %eax, %eax 48 | js go_exit 49 | entidump_end: 50 | -------------------------------------------------------------------------------- /src/decompress.S: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: decompress.S, NRV2E decompressor, 3 | * 111 bytes - optimized for size, not speed ;) 4 | */ 5 | 6 | .data 7 | .align 0 8 | .p2align 0 9 | .globl decompress 10 | .globl decompress_end 11 | .globl decompress_src 12 | .globl decompress_dest 13 | decompress: 14 | cld 15 | .byte 0xbe /* mov decompress_src, %esi */ 16 | decompress_src: .long 0 17 | lodsl 18 | xchg %eax, %edi 19 | push %edi 20 | decompr_start: 21 | or $-1, %ebp 22 | xor %ecx, %ecx 23 | xor %ebx, %ebx 24 | call ggetbit 25 | getbit: 26 | add %bl, %bl 27 | jne gotbit 28 | mov (%esi), %bl 29 | inc %esi 30 | stc 31 | adc %bl, %bl 32 | gotbit: ret 33 | decompr_literal: 34 | movsb 35 | .byte 0xb0 /* jmp decompr_loop ;) */ 36 | ggetbit: 37 | pop %edx 38 | decompr_loop: 39 | call *%edx 40 | jc decompr_literal 41 | decompr_match: 42 | xor %eax, %eax 43 | inc %eax 44 | loop: 45 | call *%edx 46 | adc %eax, %eax 47 | call *%edx 48 | jc break 49 | dec %eax 50 | call *%edx 51 | adc %eax, %eax 52 | jmp loop 53 | break: sub $3, %eax 54 | jc decompr_same_off 55 | shl $8, %eax 56 | lodsb 57 | xor $0xffffffff, %eax 58 | jz decompr_end 59 | sar %eax 60 | xchg %eax, %ebp 61 | jae decompr_got_off 62 | decompr_mlen1: 63 | call *%edx 64 | adc %ecx, %ecx 65 | jmp decompr_got_len 66 | # not reached ?! 67 | decompr_same_off: 68 | call *%edx 69 | jc decompr_mlen1 70 | decompr_got_off: 71 | inc %ecx 72 | call *%edx 73 | jc decompr_mlen1 74 | loop1: 75 | call *%edx 76 | adc %ecx, %ecx 77 | call *%edx 78 | jae loop1 79 | inc %ecx 80 | inc %ecx 81 | decompr_got_len: 82 | cmp $-0x500, %ebp 83 | adc $2, %ecx 84 | xchg %esi, %eax 85 | lea (%edi, %ebp, 1), %esi 86 | repz; movsb 87 | xchg %esi, %eax 88 | jmp decompr_loop 89 | decompr_end: 90 | /* just execute decompressed code */ 91 | ret 92 | decompress_dest: 93 | .long 0 94 | decompress_end: 95 | -------------------------------------------------------------------------------- /src/elfuck.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: elfuck.c, the main program, args parsing etc 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "elfuck.h" 11 | #include "stubify.h" 12 | 13 | void __stack_chk_fail(void) {} 14 | 15 | 16 | int usage(char *s) 17 | { 18 | eprintf("%s [-bsl0123456789] input \n" 19 | "\tb\tdon't include banner in header\n" 20 | "\ts\tscramble the file with polymorphic decryptor\n" 21 | "\tl\tlock the file by password\n" 22 | "\t1-9\tcompression level\n", s); 23 | return 1; 24 | } 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | int level = 9; 29 | char *input; 30 | char output[1024] = "output"; 31 | int i = 1; 32 | int flags = 0; 33 | 34 | printf("%s\n", BANNER); 35 | 36 | /* parse args */ 37 | if (argc < 2) 38 | return usage(argv[0]); 39 | 40 | /* arguments ? */ 41 | if (argv[1][0] == '-') { 42 | int q; 43 | char *s = argv[1]; 44 | 45 | i++; 46 | for (q = 1; q < strlen(s); q++) { 47 | if ((s[q] >= '1') && (s[q] <= '9')) { 48 | level = s[q] - '0'; 49 | continue; 50 | } 51 | switch (s[q] & 0xdf) { 52 | case 'B': 53 | flags |= FLAG_NOBANNER; 54 | break; 55 | case 'S': 56 | flags |= FLAG_SCRAMBLE; 57 | break; 58 | case 'L': 59 | flags |= FLAG_LOCK; 60 | break; 61 | default: 62 | return usage(argv[0]); 63 | } 64 | } 65 | } 66 | 67 | if (argc <= i) 68 | return usage(argv[0]); 69 | input = argv[i]; 70 | i++; 71 | if (i < argc) { 72 | strncpy(output, argv[i], sizeof(output)-1); 73 | output[sizeof(output)-1] = 0; 74 | } 75 | return pack_elf(input, output, abs(level), flags); 76 | } 77 | -------------------------------------------------------------------------------- /src/execelf.S: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: execelf.S, executing any ELF file from memory - ~400 bytes ;) 3 | */ 4 | 5 | .data 6 | .align 0 7 | .p2align 0 8 | .globl execelf 9 | .globl execelf_end 10 | .globl execelf_interp 11 | .globl e_skip_interp 12 | .globl e_no_interp 13 | 14 | #define DEBUG 0 15 | GRANT=512 16 | 17 | #if DEBUG 18 | #define PAUSE \ 19 | pushal; \ 20 | pushl $3; \ 21 | pop %eax; \ 22 | push $1; \ 23 | pop %edx; \ 24 | push %eax; \ 25 | mov %esp, %ecx; \ 26 | xor %ebx, %ebx; \ 27 | int $0x80; \ 28 | pop %eax; \ 29 | popal; 30 | #else 31 | #define PAUSE 32 | #endif 33 | 34 | execelf: 35 | //#include "antidump.S" 36 | call e_getdelta 37 | elf_error: 38 | call e_getstrings 39 | e_err1: 40 | .ascii "ELF execution failed\n" 41 | e_err2: 42 | e_getstrings: 43 | movl $4, %eax 44 | movl $2, %ebx 45 | popl %ecx 46 | movl $(e_err2-e_err1), %edx 47 | int $0x80 48 | mov $1, %eax 49 | mov $127, %ebx 50 | int $0x80 51 | e_getdelta: 52 | pop %edi 53 | add $(execelf_end-elf_error), %edi 54 | mov %edi, %ebx 55 | xor %ebp, %ebp /* interpreter base, none at this time */ 56 | xor %eax, %eax 57 | scasb 58 | jz e_no_interp 59 | e_skip_interp: 60 | scasb 61 | jnz e_skip_interp 62 | e_load_interp: 63 | /* well, try open interpreter file */ 64 | push %esi 65 | mov $5, %eax 66 | xor %ecx, %ecx 67 | int $0x80 68 | test %eax, %eax 69 | js elf_error 70 | mov $4096, %edx 71 | sub %edx, %esp /* one page for headers */ 72 | xchg %eax, %ebx /* handle to %ebx */ 73 | mov $3, %eax /* read() */ 74 | mov %esp, %ecx 75 | int $0x80 76 | 77 | mov 28(%esp), %edx /* phdrs offset */ 78 | push $0 /* last_bss */ 79 | push $0 /* elf_bss */ 80 | e_load_findseg: 81 | cmpl $1, 8(%esp, %edx) 82 | jne e_load_nextseg 83 | /* this will mmap one segment */ 84 | e_load_mapseg: 85 | mov 8+8(%esp, %edx), %eax /* vaddr offset */ 86 | mov %eax, %edi 87 | and $~4095, %edi 88 | and $4095, %eax 89 | 90 | mov 8+4(%esp, %edx), %ecx /* offset in file */ 91 | sub %eax, %ecx 92 | 93 | mov 8+16(%esp, %edx), %esi /* filesz */ 94 | add %eax, %esi 95 | 96 | push %ecx /* offset */ 97 | push %ebx /* fd */ 98 | push $0x12 /* MAP_FIXED | MAP_PRIVATE */ 99 | push $0x7 /* rwx */ 100 | push %esi /* filesize */ 101 | 102 | cmpw $3, 8+5*4+16(%esp) /* ET_DYN ?! */ 103 | jne e_load_fixed 104 | add %ebp, %edi /* relocate */ 105 | test %ebp, %ebp /* huh, base not known yet ? */ 106 | jne e_load_fixed 107 | andb $~0x10, 8(%esp) /* remove MAP_FIXED */ 108 | push $0 109 | .byte 0xb0 /* addr = 0, i.e. get random */ 110 | e_load_fixed: 111 | push %edi /* addr */ 112 | mov %esp, %ebx 113 | mov $90, %eax 114 | int $0x80 /* try mmap */ 115 | cmp $0xfffff000, %eax 116 | 1: jae elf_error /* failed ? */ 117 | 118 | testb $0x10, 12(%esp) /* was fixed ? */ 119 | jnz e_load_wasfixed 120 | sub %edi, %eax /* it's first dynamic - set base */ 121 | xchg %eax, %ebp /* to the ebp */ 122 | e_load_wasfixed: 123 | add $16, %esp 124 | pop %ebx /* restore fd */ 125 | pop %eax /* offset - blah */ 126 | 127 | mov 8+8(%esp, %edx), %ecx /* vaddr unaligned */ 128 | add %ebp, %ecx 129 | 130 | mov 8+16(%esp, %edx), %edi 131 | add %ecx, %edi /* k = load_addr + p_vaddr + p_filesz */ 132 | pop %eax /* elf_bss */ 133 | cmp %edi, %eax /* if (k > elf_bss) */ 134 | jae elf_bss_g 135 | xchg %edi, %eax /* elf_bss = k */ 136 | elf_bss_g: 137 | 138 | mov 4+20(%esp, %edx), %edi 139 | add %ecx, %edi /* k = load_addr + p_vaddr + p_memsz */ 140 | pop %esi /* last_bss */ 141 | cmp %edi, %esi 142 | jae last_bss_g 143 | mov %edi, %esi 144 | last_bss_g: 145 | pushl %esi 146 | pushl %eax 147 | 148 | e_load_nextseg: 149 | add $32, %edx 150 | decw 8+44(%esp) 151 | jnz e_load_findseg 152 | 153 | mov $6, %eax /* close that sucker */ 154 | int $0x80 155 | 156 | /* well, ladies and gantlemans, now pad zero the bss and mmap the rest of it */ 157 | pop %edi /* elf_bss */ 158 | pop %ecx /* last_bss */ 159 | lea 4095(%edi), %eax /* where we'll start mmaping to */ 160 | and $~4095, %eax 161 | sub %eax, %ecx /* size */ 162 | add $4095, %ecx /* pagealigned */ 163 | and $~4095, %ecx 164 | jecxz no_bss 165 | 166 | push $0 167 | push $0 168 | push $0x32 169 | push $0x7 170 | push %ecx 171 | push %eax 172 | mov %esp, %ebx 173 | mov $90, %eax 174 | int $0x80 175 | cmp $0xfffff000, %eax 176 | jae 1b /* failed ? */ 177 | add $24, %esp 178 | 179 | /* and also zero it */ 180 | xor %eax, %eax 181 | repz; stosb 182 | no_bss: 183 | 184 | mov 24(%esp), %eax /* yep, we need new entrypoint */ 185 | add %ebp, %eax 186 | add $4096, %esp 187 | pop %esi 188 | e_no_interp: 189 | mov %esi, %edi 190 | test %eax, %eax 191 | jnz have_ep 192 | mov 8(%edi), %eax 193 | have_ep: 194 | xchg %eax, %ebx /* entrypoint in ebx */ 195 | mov %edi, %edx /* saved-aux in edx */ 196 | 197 | /* now go count stuff */ 198 | mov %esp, %esi 199 | lea (%esp), %esi 200 | lodsl 201 | lea 4(%esi,%eax,4), %esi 202 | skip_env: 203 | lodsl 204 | test %eax, %eax 205 | jnz skip_env 206 | 207 | push %esi /* save start of aux table */ 208 | skip_aux: 209 | lodsl 210 | test %eax, %eax 211 | lodsl 212 | jnz skip_aux 213 | 214 | pop %eax 215 | 216 | sub %esp, %esi /* in esi is now size of block to be moved */ 217 | mov %esi, %ecx 218 | mov %esp, %esi 219 | sub $GRANT, %esp 220 | mov %esp, %edi 221 | repz; movsb 222 | 223 | push %ebx /* save entrypoint */ 224 | lea -512(%eax), %esi 225 | 226 | PAUSE 227 | 228 | /* push $4 229 | pop %ecx 230 | push $22 231 | pop %ebx 232 | call set_aux_ent 233 | 234 | push $6 235 | pop %ecx 236 | push $4096 237 | pop %ebx 238 | call set_aux_ent 239 | 240 | push $8 241 | pop %ecx 242 | push $0 243 | pop %ebx 244 | call set_aux_ent 245 | 246 | push $11 247 | pop %ecx 248 | push $0 249 | pop %ebx 250 | call set_aux_ent 251 | 252 | push $12 253 | pop %ecx 254 | push $0 255 | pop %ebx 256 | call set_aux_ent 257 | 258 | push $13 259 | pop %ecx 260 | push $0 261 | pop %ebx 262 | call set_aux_ent 263 | 264 | push $14 265 | pop %ecx 266 | push $0 267 | pop %ebx 268 | call set_aux_ent */ 269 | 270 | 271 | push $3 272 | pop %ecx /* AT_PHDR */ 273 | mov (%edx), %ebx 274 | call set_aux_ent 275 | mov $5, %cl /* AT_PHNUM */ 276 | mov 4(%edx), %ebx 277 | call set_aux_ent 278 | mov $7, %cl /* AT_BASE */ 279 | mov %ebp, %ebx 280 | call set_aux_ent 281 | mov $9, %cl /* AT_ENTRY */ 282 | mov 8(%edx), %ebx 283 | call set_aux_ent 284 | 285 | /* now, free our unused pages and fire that sucker up */ 286 | push $91 287 | pop %eax 288 | movl 12(%edx), %ebx 289 | movl 16(%edx), %ecx 290 | int $0x80 291 | xor %eax, %eax 292 | xor %ebx, %ebx 293 | xor %ecx, %ecx 294 | xor %edx, %edx 295 | xor %esi, %esi 296 | xor %edi, %edi 297 | xor %ebp, %ebp 298 | ret /* voila! */ 299 | 300 | /* this will setup new/modify existing aux entry, well on buggy 301 | < 2.2.17 kernels we're going to overwrite envp, but heck, it 302 | seem to work fine -sd */ 303 | set_aux_ent: 304 | push %esi 305 | set_aux_find: 306 | lodsl 307 | test %eax, %eax 308 | jz set_aux_new 309 | cmp %ecx, %eax 310 | lodsl 311 | jne set_aux_find 312 | mov %ebx, -4(%esi) 313 | set_aux_done: 314 | pop %esi 315 | ret 316 | set_aux_new: 317 | mov %ecx, -4(%esi) 318 | mov %ebx, (%esi) 319 | and $0, 4(%esi) 320 | jmp set_aux_done 321 | 322 | execelf_end: 323 | execelf_interp: .zero 256 324 | 325 | 326 | 327 | -------------------------------------------------------------------------------- /src/getpw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: getpw.c, password input 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "elfuck.h" 13 | #include "lock.h" 14 | #include "getpw.h" 15 | 16 | /* this will return a 20byte hash of entered password */ 17 | void getpassw(uchar *hash) 18 | { 19 | struct termios old, new; 20 | char p1[MAXPASS], p2[MAXPASS]; 21 | int len1, len2; 22 | 23 | /* get old term settings */ 24 | tcgetattr(0, &old); 25 | new = old; 26 | new.c_lflag &= ~(ECHO); 27 | tcsetattr(0, TCSAFLUSH, &new); 28 | while (1) { 29 | printf("Password: "); fflush(stdout); 30 | len1 = read(0, p1, sizeof(p1)-1); 31 | if (--len1 < 0) goto bad; 32 | p1[len1] = 0; 33 | putchar('\n'); 34 | printf("Retype password:"); fflush(stdout); 35 | len2 = read(0, p2, sizeof(p2)-1); 36 | if (--len2 < 0) goto bad; 37 | p2[len2] = 0; 38 | putchar('\n'); 39 | if ((len1 != len2) || (strcmp(p1, p2))) { 40 | bad: 41 | printf("Sorry, passwords do not match\n"); 42 | continue; 43 | } 44 | break; 45 | } 46 | tcsetattr(0, TCSAFLUSH, &old); 47 | sha1_asm(hash, p1, len1); 48 | } 49 | -------------------------------------------------------------------------------- /src/lock.S: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: lock.S, file locking, sha1 & rc4 (~400 & ~80 bytes) 3 | */ 4 | 5 | #define __ASSEMBLY__ 6 | #include "getpw.h" 7 | 8 | .globl elf_lock 9 | .globl lock_start 10 | .globl lock_testkey 11 | .globl elf_lock_end 12 | .globl rc4_asm 13 | .globl sha1_asm 14 | .globl locked_len 15 | 16 | .data 17 | .align 0 18 | .p2align 0 19 | 20 | elf_lock: 21 | .byte 0xbd /* mov lock_start, %ebp */ 22 | lock_start: .long 0 /* ptr to encrypted data */ 23 | mov %esp, %esi 24 | sub $(64+MAXPASS), %esp /* 60 bytes - password, 64 bytes - terminfo */ 25 | cld 26 | lodsl 27 | lea 4(%esi, %eax, 4), %esi 28 | /* walk thru env and look for 'EPW=' */ 29 | find_env: 30 | lodsl 31 | test %eax, %eax 32 | jz find_env_end 33 | 34 | cmpl $0x3d575045, (%eax) /* cmp 'EPW=', (%eax) */ 35 | jne find_env 36 | lea 4(%eax), %esi 37 | jmp have_pass 38 | find_env_end: 39 | get_pass: 40 | push $4 41 | pop %eax 42 | xor %ebx, %ebx 43 | inc %ebx 44 | mov -4(%ebp), %edx /* size of banner (negative!) */ 45 | lea -4(%ebp, %edx), %ecx 46 | neg %edx 47 | int $0x80 48 | /* we'must explicitly read password from stdin 49 | * ioctl(TCGETS ... */ 50 | pushl $54 51 | popl %eax /* ioctl */ 52 | xor %ebx, %ebx /* stdin */ 53 | mov $0x5401, %ecx /* TCGETS */ 54 | mov %esp, %edx 55 | int $0x80 56 | test %eax, %eax 57 | jnz err_out 58 | ioctl_ok: 59 | pushl 12(%edx) 60 | andb $0xf7, 12(%edx) /* &= ~(ECHO) */ 61 | inc %ecx /* 0x5402 - TCSETS */ 62 | mov $54, %al 63 | push %eax 64 | int $0x80 65 | 66 | push %ecx 67 | push %edx 68 | mov $3, %al 69 | lea 64(%esp), %ecx 70 | mov %ecx, %esi 71 | push $MAXPASS 72 | pop %edx /* maximal password - 60 chrs */ 73 | int $0x80 74 | dec %eax 75 | jns 1f 76 | err_out: 77 | xchg %eax, %ebx 78 | xor %eax, %eax 79 | inc %eax 80 | int $0x80 81 | 1: 82 | movb %ah, (%ecx, %eax) /* terminate string (yah, including \n) */ 83 | 84 | pop %edx /* restore original terminfo */ 85 | pop %ecx 86 | pop %eax 87 | popl 12(%edx) 88 | int $0x80 89 | 90 | /* write newline */ 91 | mov $4, %al 92 | inc %ebx 93 | push $0xa 94 | mov %esp, %ecx 95 | push $1 96 | pop %edx 97 | int $0x80 98 | pop %eax 99 | have_pass: 100 | xor %ecx, %ecx 101 | push %esi 102 | .byte 0xb0 103 | 1: inc %ecx 104 | lodsb 105 | test %al, %al 106 | jnz 1b 107 | pop %esi 108 | mov %esp, %edi 109 | call sha1 /* and compute hash of password! */ 110 | /* well, now use the password hash value as decryption key */ 111 | .byte 0xb9 /* mov locked_len, %ecx */ 112 | locked_len: .long 0 113 | mov %ebp, %esi 114 | /* 115 | * edi - key (hashed) 116 | * esi - input data 117 | * ecx - length 118 | */ 119 | call rc4 /* decrypt */ 120 | push %edi 121 | add $20, %edi 122 | call sha1 /* compute sha1 of result */ 123 | .byte 0x81, 0x3f /* cmp $lock_testkey, (%edi) */ 124 | lock_testkey:.long 0 125 | pop %edi 126 | je decrypt_ok 127 | call rc4 /* repair back ;) */ 128 | call 1f 129 | .ascii "bad password\n" 130 | 1: pop %ecx 131 | push $4 132 | pop %eax 133 | push $2 134 | pop %ebx 135 | pushl $13 136 | pop %edx 137 | int $0x80 138 | jmp get_pass /* try again ;) */ 139 | decrypt_ok: 140 | add $(64+MAXPASS), %esp 141 | jmp *%ebp /* jump to decrypted proggie */ 142 | 143 | /* 144 | * RC4 implementation, 20 byte key assumed 145 | * edi - key 146 | * esi - data 147 | * ecx - datalen 148 | */ 149 | rc4: 150 | pushal 151 | mov %esp, %ebp 152 | xor %eax, %eax 153 | 1: dec %esp 154 | inc %al 155 | jnz 1b 156 | 1: movb %al, (%esp, %eax) 157 | inc %al 158 | jnz 1b /* eax = 0 index2 */ 159 | cdq /* edx = 0, counter */ 160 | xor %ebx, %ebx /* ebx = 0 index1 */ 161 | 2: addb (%edi, %ebx), %al 162 | addb (%esp, %edx), %al 163 | movb (%esp, %edx), %bh 164 | xchgb %bh, (%esp, %eax) 165 | movb %bh, (%esp, %edx) 166 | xor %bh, %bh 167 | inc %ebx 168 | cmp $20, %bl /* <-- put key len there! */ 169 | jc 1f 170 | and %bh, %bl 171 | 1: inc %dl 172 | jnz 2b 173 | cdq /* edx = 0, x */ 174 | xor %ebx, %ebx /* ebx = 0, y */ 175 | 1: inc %dl 176 | addb (%esp, %edx), %bl 177 | movb (%esp, %edx), %al 178 | xchgb %al, (%esp, %ebx) 179 | movb %al, (%esp, %edx) 180 | addb (%esp, %ebx), %al 181 | mov (%esp, %eax), %al 182 | xor %al, (%esi) 183 | inc %esi 184 | loop 1b 185 | mov %ebp, %esp 186 | popa 187 | ret 188 | rc4_end: 189 | 190 | /* 191 | * minimalistic implementation of sha1 in x86 asm, ~400 bytes 192 | * esi - input bytes 193 | * ecx - number of input bytes 194 | * edi - 20 bytes of digest 195 | */ 196 | sha1: 197 | pusha 198 | push %edi 199 | pushl $0x67452301 /* state[0] */ 200 | pushl $0xEFCDAB89 /* state[1] */ 201 | pushl $0x98BADCFE /* state[2] */ 202 | pushl $0x10325476 /* state[3] */ 203 | pushl $0xC3D2E1F0 /* state[4] */ 204 | mov %ecx, %eax 205 | mov %ecx, %ebp 206 | shl $3, %eax 207 | bswap %eax /* sha1 works with big endian only ;( */ 208 | push %eax /* count[0] */ 209 | sub $128, %esp /* for padding stuff */ 210 | trans_loop: 211 | cmp $64, %ecx 212 | jc gopad1 213 | call transform 214 | add $64, %esi 215 | sub $64, %ecx 216 | jmp trans_loop 217 | gopad1: 218 | mov %esp, %edi 219 | push %ecx 220 | repz; movsb 221 | movb $0x80, %al /* padding mark */ 222 | stosb 223 | pop %ebx 224 | mov $127, %cl 225 | sub %ebx, %ecx 226 | xor %eax, %eax 227 | repz; stosb 228 | mov %esp, %esi /* start to esi */ 229 | inc %ecx 230 | mov 127(%esi,%ecx), %eax /* size to eax */ 231 | cmp $56, %ebx 232 | jc single_align 233 | double_align: 234 | mov %eax, 124(%esi) 235 | call transform 236 | add $64, %esi 237 | .byte 0xba 238 | single_align: 239 | mov %eax, 60(%esp) 240 | call transform 241 | add $128+4, %esp 242 | 243 | mov $5, %cl 244 | mov 20(%esp), %edi 245 | 1: mov -4(%esp, %ecx, 4), %eax 246 | bswap %eax 247 | stosl 248 | loop 1b 249 | add $24, %esp 250 | popa 251 | ret 252 | 253 | /* 254 | * well, this is the main SHA1 function 255 | * it must preserve all registers 256 | * 0(%esp) - count - unused 257 | * 4(%esp) - state[4] 258 | * 8(%esp) - state[3] 259 | * 12(%esp) - state[2] 260 | * 16(%esp) - state[1] 261 | * 20(%esp) - state[0] 262 | */ 263 | transform: 264 | pusha 265 | /* create private copy of processed data */ 266 | pushl $64 267 | popl %ecx 268 | sub %ecx, %esp 269 | mov %esp, %edi 270 | repz; movsb 271 | mov %esp, %esi 272 | 273 | add $128+36+4, %edi 274 | 275 | mov 16(%edi), %ebp 276 | mov 12(%edi), %eax 277 | mov 8(%edi), %ebx 278 | mov 4(%edi), %edx 279 | mov (%edi), %edi 280 | 281 | /* 282 | * e = a 283 | * a = b 284 | * b = c 285 | * c = d 286 | * d = e 287 | */ 288 | xor %ecx, %ecx 289 | aloop: 290 | # rotate a,b,c,d,e 291 | push %eax 292 | push %ebx 293 | push %edx 294 | push %edi 295 | push %ebp 296 | pop %eax 297 | pop %ebp 298 | pop %edi 299 | pop %edx 300 | pop %ebx 301 | 302 | #!# 303 | push %edx 304 | call rop 305 | push %eax 306 | rol $5, %eax 307 | add %eax, %edx 308 | pop %eax 309 | add %edx, %ebp 310 | rol $30, %ebx 311 | pop %edx 312 | 313 | inc %ecx 314 | cmp $80, %cl 315 | jc aloop 316 | add $64, %esp 317 | 318 | lea 128+36+4(%esp), %ecx 319 | 320 | add %ebp, 16(%ecx) 321 | add %eax, 12(%ecx) 322 | add %ebx, 8(%ecx) 323 | add %edx, 4(%ecx) 324 | add %edi, (%ecx) 325 | 326 | popa 327 | ret 328 | 329 | rop: 330 | cmp $20, %cl 331 | jae r2 332 | /* 333 | * R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); 334 | * R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); 335 | */ 336 | r0: 337 | xor %edi, %edx /* x = x^y */ 338 | and %ebx, %edx /* x = x&w */ 339 | xor %edi, %edx /* x = x^y */ 340 | 341 | cmp $20, %cl 342 | jae r2 343 | cmp $16, %cl 344 | jae r1 345 | r0_: 346 | push %eax 347 | mov (%esi, %ecx, 4), %eax /* x += blk0(i) */ 348 | bswap %eax 349 | mov %eax, (%esi, %ecx, 4) 350 | add %eax, %edx 351 | pop %eax 352 | jmp rx 353 | r1: 354 | call blk 355 | rx: add $0x5A827999, %edx 356 | rall: ret 357 | 358 | /* 359 | * R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); 360 | * R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); 361 | */ 362 | 363 | r2: 364 | cmp $40, %cl 365 | jae mayber3 366 | r2r4: 367 | xor %ebx, %edx /* x^w */ 368 | xor %edi, %edx /* ^y */ 369 | call blk 370 | add $0x6ED9EBA1, %edx 371 | cmp $60, %cl 372 | jc rall 373 | /* alternatively R4 */ 374 | add $(0xCA62C1D6-0x6ED9EBA1), %edx 375 | ret 376 | mayber3: 377 | cmp $60, %cl 378 | jae r2r4 379 | r3: 380 | /* R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); */ 381 | push %edx 382 | or %ebx, %edx /* x|w */ 383 | and %edi, %edx /* &y */ 384 | and %ebx, (%esp) 385 | or (%esp), %edx 386 | add $4, %esp 387 | call blk 388 | add $0x8F1BBCDC, %edx 389 | ret 390 | 391 | /* 392 | * this performs block expand function 393 | * blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ 394 | * ^block->l[(i+2)&15]^block->l[i&15],1)) 395 | * i => ecx 396 | * result will be added to X (%edx), block itself is in esi 397 | */ 398 | blk: 399 | pusha 400 | lea 13(%ecx), %eax 401 | and $15, %al /* block->l[(i+13)&15] = ebx */ 402 | lea 8(%ecx), %ebx 403 | and $15, %bl /* block->l[(i+8)&15] = ebx */ 404 | lea 2(%ecx), %edx 405 | and $15, %dl /* block->l[(i+2)&15] = edx */ 406 | and $15, %cl /* block->l[i&15] = ecx */ 407 | 408 | mov (%esi, %eax, 4), %edi /* block->l[i&15] */ 409 | xor (%esi, %ebx, 4), %edi /* ^block->l[(i+8)&15] */ 410 | xor (%esi, %edx, 4), %edi /* ^block->l[(i+2)&15] */ 411 | xor (%esi, %ecx, 4), %edi /* ^block->l[i&15] */ 412 | rol $1, %edi /* rol 1 */ 413 | mov %edi, (%esi, %ecx, 4) /* result to block->l[i&15] */ 414 | add %edi, 20(%esp) /* add to pushed %edx */ 415 | popa 416 | ret 417 | sha1_end: 418 | elf_lock_end: 419 | 420 | /* just a C interfaces */ 421 | 422 | /* sha1_asm(char *digest, char *input, int len) */ 423 | sha1_asm: 424 | pushal 425 | mov 32+4(%esp), %edi 426 | mov 32+8(%esp), %esi 427 | mov 32+12(%esp), %ecx 428 | call sha1 429 | popal 430 | ret 431 | 432 | /* rc4_asm(char *key, char *input, int len) */ 433 | rc4_asm: 434 | pushal 435 | mov 32+4(%esp), %edi 436 | mov 32+8(%esp), %esi 437 | mov 32+12(%esp), %ecx 438 | call rc4 439 | popal 440 | ret 441 | -------------------------------------------------------------------------------- /src/nrv2e.c: -------------------------------------------------------------------------------- 1 | /* nrv2e -- implementation of the NRV2E-99 compression algorithm 2 | 3 | This file was part of the UCL data compression library. 4 | 5 | Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer 6 | All Rights Reserved. 7 | 8 | The UCL library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License as 10 | published by the Free Software Foundation; either version 2 of 11 | the License, or (at your option) any later version. 12 | 13 | The UCL library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with the UCL library; see the file COPYING. 20 | If not, write to the Free Software Foundation, Inc., 21 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 | 23 | Markus F.X.J. Oberhumer 24 | 25 | http://www.oberhumer.com/opensource/ucl/ 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | //#include 40 | #define assert(x) 41 | 42 | 43 | #define ucl_memcpy memcpy 44 | #define ucl_malloc malloc 45 | #define ucl_alloc(x,y) malloc(x*y) 46 | #define ucl_free free 47 | #define ucl_memcmp memcmp 48 | #define ucl_memset memset 49 | #define ucl_sizeof(x) (sizeof(x)) 50 | #define UCL_PUBLIC(x) x 51 | 52 | #define NRV2E 53 | //#define __UCL_CHECKER 54 | 55 | #define UCL_BYTE(x) ((unsigned char) (x)) 56 | #define UCL_USHORT(x) ((unsigned short) ((x) & 0xffff)) 57 | #define UCL_MAX(a,b) ((a) >= (b) ? (a) : (b)) 58 | #define UCL_MIN(a,b) ((a) <= (b) ? (a) : (b)) 59 | #define UCL_MAX3(a,b,c) ((a) >= (b) ? UCL_MAX(a,c) : UCL_MAX(b,c)) 60 | #define UCL_MIN3(a,b,c) ((a) <= (b) ? UCL_MIN(a,c) : UCL_MIN(b,c)) 61 | 62 | 63 | #define UCL_E_OK 0 64 | #define UCL_E_ERROR (-1) 65 | #define UCL_E_INVALID_ARGUMENT (-2) 66 | #define UCL_E_OUT_OF_MEMORY (-3) 67 | /* compression errors */ 68 | #define UCL_E_NOT_COMPRESSIBLE (-101) 69 | /* decompression errors */ 70 | #define UCL_E_INPUT_OVERRUN (-201) 71 | #define UCL_E_OUTPUT_OVERRUN (-202) 72 | #define UCL_E_LOOKBEHIND_OVERRUN (-203) 73 | #define UCL_E_EOF_NOT_FOUND (-204) 74 | #define UCL_E_INPUT_NOT_CONSUMED (-205) 75 | #define UCL_E_OVERLAP_OVERRUN (-206) 76 | 77 | typedef unsigned int ucl_uint32; 78 | typedef int ucl_int32; 79 | #define UCL_UINT32_MAX 0xffffffffUL 80 | #define UCL_INT32_MAX INT_MAX 81 | #define UCL_INT32_MIN INT_MIN 82 | typedef unsigned int ucl_uint; 83 | typedef int ucl_int; 84 | #define UCL_UINT_MAX UINT_MAX 85 | #define UCL_INT_MAX INT_MAX 86 | #define UCL_INT_MIN INT_MIN 87 | #define UCL_UINT32_C(c) c ## UL 88 | #define UCL_UNUSED(x) x = x 89 | 90 | 91 | struct ucl_compress_config_t { 92 | int bb_endian; 93 | int bb_size; 94 | ucl_uint max_offset; 95 | ucl_uint max_match; 96 | int s_level; 97 | int h_level; 98 | int p_level; 99 | int c_flags; 100 | ucl_uint m_size; 101 | }; 102 | #define ucl_compress_config_p ucl_compress_config_t * 103 | 104 | #define ucl_byte unsigned char 105 | #define ucl_bytep unsigned char * 106 | #define ucl_charp char * 107 | #define ucl_voidp void * 108 | #define ucl_shortp short * 109 | #define ucl_ushortp unsigned short * 110 | #define ucl_uint32p ucl_uint32 * 111 | #define ucl_int32p ucl_int32 * 112 | #define ucl_uintp ucl_uint * 113 | #define ucl_intp ucl_int * 114 | #define ucl_voidpp ucl_voidp * 115 | #define ucl_bytepp ucl_bytep * 116 | #define ucl_bool int 117 | 118 | /* a progress indicator callback function */ 119 | typedef struct { 120 | void (*callback) (ucl_uint, ucl_uint, int, ucl_voidp user); 121 | ucl_voidp user; 122 | } ucl_progress_callback_t; 123 | #define ucl_progress_callback_p ucl_progress_callback_t * 124 | 125 | 126 | #define N (1024*1024ul) /* size of ring buffer */ 127 | //#define SWD_USE_MALLOC 128 | #define SWD_HSIZE 65536ul 129 | 130 | #if 1 131 | #define THRESHOLD 1 /* lower limit for match length */ 132 | #define F 16384 /* upper limit for match length */ 133 | #else 134 | #define THRESHOLD 1 /* lower limit for match length */ 135 | #define F 2048 /* upper limit for match length */ 136 | #endif 137 | 138 | #define UCL_COMPRESS_T ucl_nrv2e_t 139 | #define ucl_swd_t ucl_nrv2e_swd_t 140 | #define ucl_nrv_99_compress ucl_nrv2e_99_compress 141 | #define M2_MAX_OFFSET 0x500 142 | #define ucl_swd_p ucl_swd_t * 143 | 144 | typedef struct { 145 | int init; 146 | 147 | ucl_uint look; /* bytes in lookahead buffer */ 148 | 149 | ucl_uint m_len; 150 | ucl_uint m_off; 151 | 152 | ucl_uint last_m_len; 153 | ucl_uint last_m_off; 154 | 155 | const ucl_byte *bp; 156 | const ucl_byte *ip; 157 | const ucl_byte *in; 158 | const ucl_byte *in_end; 159 | ucl_byte *out; 160 | 161 | ucl_uint32 bb_b; 162 | unsigned bb_k; 163 | unsigned bb_c_endian; 164 | unsigned bb_c_s; 165 | unsigned bb_c_s8; 166 | ucl_byte *bb_p; 167 | ucl_byte *bb_op; 168 | 169 | struct ucl_compress_config_t conf; 170 | ucl_uintp result; 171 | 172 | ucl_progress_callback_p cb; 173 | 174 | ucl_uint textsize; /* text size counter */ 175 | ucl_uint codesize; /* code size counter */ 176 | ucl_uint printcount; /* counter for reporting progress every 1K bytes */ 177 | 178 | /* some stats */ 179 | unsigned long lit_bytes; 180 | unsigned long match_bytes; 181 | unsigned long rep_bytes; 182 | unsigned long lazy; 183 | } UCL_COMPRESS_T; 184 | 185 | #define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1)) 186 | 187 | #ifndef SWD_N 188 | # define SWD_N N 189 | #endif 190 | #ifndef SWD_F 191 | # define SWD_F F 192 | #endif 193 | #ifndef SWD_THRESHOLD 194 | # define SWD_THRESHOLD THRESHOLD 195 | #endif 196 | 197 | /* unsigned type for dictionary access - don't waste memory here */ 198 | #if (SWD_N + SWD_F + SWD_F < USHRT_MAX) 199 | typedef unsigned short swd_uint; 200 | # define SWD_UINT_MAX USHRT_MAX 201 | #else 202 | typedef ucl_uint swd_uint; 203 | # define SWD_UINT_MAX UCL_UINT_MAX 204 | #endif 205 | #define SWD_UINT(x) ((swd_uint)(x)) 206 | 207 | 208 | #ifndef SWD_HSIZE 209 | # define SWD_HSIZE 16384 210 | #endif 211 | #ifndef SWD_MAX_CHAIN 212 | # define SWD_MAX_CHAIN 2048 213 | #endif 214 | 215 | #if !defined(HEAD3) 216 | #if 1 217 | # define HEAD3(b,p) \ 218 | (((0x9f5f*(((((ucl_uint32)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1)) 219 | #else 220 | # define HEAD3(b,p) \ 221 | (((0x9f5f*(((((ucl_uint32)b[p+2]<<5)^b[p+1])<<5)^b[p]))>>5) & (SWD_HSIZE-1)) 222 | #endif 223 | #endif 224 | 225 | #if (SWD_THRESHOLD == 1) && !defined(HEAD2) 226 | # if 1 && defined(UCL_UNALIGNED_OK_2) 227 | # define HEAD2(b,p) (* (const ucl_ushortp) &(b[p])) 228 | # else 229 | # define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8)) 230 | # endif 231 | # define NIL2 SWD_UINT_MAX 232 | #endif 233 | 234 | 235 | #if defined(__UCL_CHECKER) 236 | /* malloc arrays of the exact size to detect any overrun */ 237 | # ifndef SWD_USE_MALLOC 238 | # define SWD_USE_MALLOC 239 | # endif 240 | #endif 241 | 242 | 243 | typedef struct { 244 | /* public - "built-in" */ 245 | ucl_uint n; 246 | ucl_uint f; 247 | ucl_uint threshold; 248 | 249 | /* public - configuration */ 250 | ucl_uint max_chain; 251 | ucl_uint nice_length; 252 | ucl_bool use_best_off; 253 | ucl_uint lazy_insert; 254 | 255 | /* public - output */ 256 | ucl_uint m_len; 257 | ucl_uint m_off; 258 | ucl_uint look; 259 | int b_char; 260 | #if defined(SWD_BEST_OFF) 261 | ucl_uint best_off[SWD_BEST_OFF]; 262 | #endif 263 | 264 | /* semi public */ 265 | UCL_COMPRESS_T *c; 266 | ucl_uint m_pos; 267 | #if defined(SWD_BEST_OFF) 268 | ucl_uint best_pos[SWD_BEST_OFF]; 269 | #endif 270 | 271 | /* private */ 272 | const ucl_byte *dict; 273 | const ucl_byte *dict_end; 274 | ucl_uint dict_len; 275 | 276 | /* private */ 277 | ucl_uint ip; /* input pointer (lookahead) */ 278 | ucl_uint bp; /* buffer pointer */ 279 | ucl_uint rp; /* remove pointer */ 280 | ucl_uint b_size; 281 | 282 | unsigned char *b_wrap; 283 | 284 | ucl_uint node_count; 285 | ucl_uint first_rp; 286 | 287 | #if defined(SWD_USE_MALLOC) 288 | unsigned char *b; 289 | swd_uint *head3; 290 | swd_uint *succ3; 291 | swd_uint *best3; 292 | swd_uint *llen3; 293 | #ifdef HEAD2 294 | swd_uint *head2; 295 | #endif 296 | #else 297 | unsigned char b[SWD_N + SWD_F + SWD_F]; 298 | swd_uint head3[SWD_HSIZE]; 299 | swd_uint succ3[SWD_N + SWD_F]; 300 | swd_uint best3[SWD_N + SWD_F]; 301 | swd_uint llen3[SWD_HSIZE]; 302 | #ifdef HEAD2 303 | swd_uint head2[UCL_UINT32_C(65536)]; 304 | #endif 305 | #endif 306 | } ucl_swd_t; 307 | 308 | 309 | /* Access macro for head3. 310 | * head3[key] may be uninitialized if the list is emtpy, 311 | * but then its value will never be used. 312 | */ 313 | #if defined(__UCL_CHECKER) 314 | # define s_head3(s,key) \ 315 | ((s->llen3[key] == 0) ? SWD_UINT_MAX : s->head3[key]) 316 | #else 317 | # define s_head3(s,key) s->head3[key] 318 | #endif 319 | 320 | 321 | /*********************************************************************** 322 | // 323 | ************************************************************************/ 324 | 325 | static 326 | void swd_initdict(ucl_swd_t * s, const ucl_byte * dict, 327 | ucl_uint dict_len) 328 | { 329 | s->dict = s->dict_end = NULL; 330 | s->dict_len = 0; 331 | 332 | if (!dict || dict_len <= 0) 333 | return; 334 | if (dict_len > s->n) { 335 | dict += dict_len - s->n; 336 | dict_len = s->n; 337 | } 338 | 339 | s->dict = dict; 340 | s->dict_len = dict_len; 341 | s->dict_end = dict + dict_len; 342 | ucl_memcpy(s->b, dict, dict_len); 343 | s->ip = dict_len; 344 | } 345 | 346 | 347 | static 348 | void swd_insertdict(ucl_swd_t * s, ucl_uint node, ucl_uint len) 349 | { 350 | ucl_uint key; 351 | 352 | s->node_count = s->n - len; 353 | s->first_rp = node; 354 | 355 | while (len-- > 0) { 356 | key = HEAD3(s->b, node); 357 | s->succ3[node] = s_head3(s, key); 358 | s->head3[key] = SWD_UINT(node); 359 | s->best3[node] = SWD_UINT(s->f + 1); 360 | s->llen3[key]++; 361 | assert(s->llen3[key] <= s->n); 362 | 363 | #ifdef HEAD2 364 | key = HEAD2(s->b, node); 365 | s->head2[key] = SWD_UINT(node); 366 | #endif 367 | 368 | node++; 369 | } 370 | } 371 | 372 | 373 | /*********************************************************************** 374 | // 375 | ************************************************************************/ 376 | 377 | static 378 | int swd_init(ucl_swd_t * s, const ucl_byte * dict, ucl_uint dict_len) 379 | { 380 | ucl_uint i = 0; 381 | int c = 0; 382 | 383 | if (s->n == 0) 384 | s->n = SWD_N; 385 | if (s->f == 0) 386 | s->f = SWD_F; 387 | s->threshold = SWD_THRESHOLD; 388 | if (s->n > SWD_N || s->f > SWD_F) 389 | return UCL_E_INVALID_ARGUMENT; 390 | 391 | #if defined(SWD_USE_MALLOC) 392 | s->b = (unsigned char *) ucl_alloc(s->n + s->f + s->f, 1); 393 | s->head3 = (swd_uint *) ucl_alloc(SWD_HSIZE, sizeof(*s->head3)); 394 | s->succ3 = (swd_uint *) ucl_alloc(s->n + s->f, sizeof(*s->succ3)); 395 | s->best3 = (swd_uint *) ucl_alloc(s->n + s->f, sizeof(*s->best3)); 396 | s->llen3 = (swd_uint *) ucl_alloc(SWD_HSIZE, sizeof(*s->llen3)); 397 | if (!s->b || !s->head3 || !s->succ3 || !s->best3 || !s->llen3) 398 | return UCL_E_OUT_OF_MEMORY; 399 | #ifdef HEAD2 400 | s->head2 = 401 | (swd_uint *) ucl_alloc(UCL_UINT32_C(65536), sizeof(*s->head2)); 402 | if (!s->head2) 403 | return UCL_E_OUT_OF_MEMORY; 404 | #endif 405 | #endif 406 | 407 | /* defaults */ 408 | s->max_chain = SWD_MAX_CHAIN; 409 | s->nice_length = s->f; 410 | s->use_best_off = 0; 411 | s->lazy_insert = 0; 412 | 413 | s->b_size = s->n + s->f; 414 | if (s->b_size + s->f >= SWD_UINT_MAX) 415 | return UCL_E_ERROR; 416 | s->b_wrap = s->b + s->b_size; 417 | s->node_count = s->n; 418 | 419 | ucl_memset(s->llen3, 0, sizeof(s->llen3[0]) * SWD_HSIZE); 420 | #ifdef HEAD2 421 | #if 1 422 | ucl_memset(s->head2, 0xff, 423 | sizeof(s->head2[0]) * UCL_UINT32_C(65536)); 424 | assert(s->head2[0] == NIL2); 425 | #else 426 | for (i = 0; i < UCL_UINT32_C(65536); i++) 427 | s->head2[i] = NIL2; 428 | #endif 429 | #endif 430 | 431 | s->ip = 0; 432 | swd_initdict(s, dict, dict_len); 433 | s->bp = s->ip; 434 | s->first_rp = s->ip; 435 | 436 | assert(s->ip + s->f <= s->b_size); 437 | #if 1 438 | s->look = (ucl_uint) (s->c->in_end - s->c->ip); 439 | if (s->look > 0) { 440 | if (s->look > s->f) 441 | s->look = s->f; 442 | ucl_memcpy(&s->b[s->ip], s->c->ip, s->look); 443 | s->c->ip += s->look; 444 | s->ip += s->look; 445 | } 446 | #else 447 | s->look = 0; 448 | while (s->look < s->f) { 449 | if ((c = getbyte(*(s->c))) < 0) 450 | break; 451 | s->b[s->ip] = UCL_BYTE(c); 452 | s->ip++; 453 | s->look++; 454 | } 455 | #endif 456 | if (s->ip == s->b_size) 457 | s->ip = 0; 458 | 459 | if (s->look >= 2 && s->dict_len > 0) 460 | swd_insertdict(s, 0, s->dict_len); 461 | 462 | s->rp = s->first_rp; 463 | if (s->rp >= s->node_count) 464 | s->rp -= s->node_count; 465 | else 466 | s->rp += s->b_size - s->node_count; 467 | 468 | #if defined(__UCL_CHECKER) 469 | /* initialize memory for the first few HEAD3 (if s->ip is not far 470 | * enough ahead to do this job for us). The value doesn't matter. */ 471 | if (s->look < 3) 472 | ucl_memset(&s->b[s->bp + s->look], 0, 3); 473 | #endif 474 | 475 | UCL_UNUSED(i); 476 | UCL_UNUSED(c); 477 | return UCL_E_OK; 478 | } 479 | 480 | 481 | static 482 | void swd_exit(ucl_swd_t * s) 483 | { 484 | #if defined(SWD_USE_MALLOC) 485 | /* free in reverse order of allocations */ 486 | #ifdef HEAD2 487 | ucl_free(s->head2); 488 | s->head2 = NULL; 489 | #endif 490 | ucl_free(s->llen3); 491 | s->llen3 = NULL; 492 | ucl_free(s->best3); 493 | s->best3 = NULL; 494 | ucl_free(s->succ3); 495 | s->succ3 = NULL; 496 | ucl_free(s->head3); 497 | s->head3 = NULL; 498 | ucl_free(s->b); 499 | s->b = NULL; 500 | #else 501 | UCL_UNUSED(s); 502 | #endif 503 | } 504 | 505 | 506 | #define swd_pos2off(s,pos) \ 507 | (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp)) 508 | 509 | 510 | /*********************************************************************** 511 | // 512 | ************************************************************************/ 513 | 514 | static __inline__ void swd_getbyte(ucl_swd_t * s) 515 | { 516 | int c; 517 | 518 | if ((c = getbyte(*(s->c))) < 0) { 519 | if (s->look > 0) 520 | --s->look; 521 | #if defined(__UCL_CHECKER) 522 | /* initialize memory - value doesn't matter */ 523 | s->b[s->ip] = 0; 524 | if (s->ip < s->f) 525 | s->b_wrap[s->ip] = 0; 526 | #endif 527 | } else { 528 | s->b[s->ip] = UCL_BYTE(c); 529 | if (s->ip < s->f) 530 | s->b_wrap[s->ip] = UCL_BYTE(c); 531 | } 532 | if (++s->ip == s->b_size) 533 | s->ip = 0; 534 | if (++s->bp == s->b_size) 535 | s->bp = 0; 536 | if (++s->rp == s->b_size) 537 | s->rp = 0; 538 | } 539 | 540 | 541 | /*********************************************************************** 542 | // remove node from lists 543 | ************************************************************************/ 544 | 545 | static __inline__ void swd_remove_node(ucl_swd_t * s, ucl_uint node) 546 | { 547 | if (s->node_count == 0) { 548 | ucl_uint key; 549 | 550 | #ifdef UCL_DEBUG 551 | if (s->first_rp != UCL_UINT_MAX) { 552 | if (node != s->first_rp) 553 | printf 554 | ("Remove %5d: %5d %5d %5d %5d %6d %6d\n", 555 | node, s->rp, s->ip, s->bp, 556 | s->first_rp, s->ip - node, 557 | s->ip - s->bp); 558 | assert(node == s->first_rp); 559 | s->first_rp = UCL_UINT_MAX; 560 | } 561 | #endif 562 | 563 | key = HEAD3(s->b, node); 564 | assert(s->llen3[key] > 0); 565 | --s->llen3[key]; 566 | 567 | #ifdef HEAD2 568 | key = HEAD2(s->b, node); 569 | assert(s->head2[key] != NIL2); 570 | if ((ucl_uint) s->head2[key] == node) 571 | s->head2[key] = NIL2; 572 | #endif 573 | } else 574 | --s->node_count; 575 | } 576 | 577 | 578 | /*********************************************************************** 579 | // 580 | ************************************************************************/ 581 | 582 | static 583 | void swd_accept(ucl_swd_t * s, ucl_uint n) 584 | { 585 | assert(n <= s->look); 586 | 587 | if (n > 0) 588 | do { 589 | ucl_uint key; 590 | 591 | swd_remove_node(s, s->rp); 592 | 593 | /* add bp into HEAD3 */ 594 | key = HEAD3(s->b, s->bp); 595 | s->succ3[s->bp] = s_head3(s, key); 596 | s->head3[key] = SWD_UINT(s->bp); 597 | s->best3[s->bp] = SWD_UINT(s->f + 1); 598 | s->llen3[key]++; 599 | assert(s->llen3[key] <= s->n); 600 | 601 | #ifdef HEAD2 602 | /* add bp into HEAD2 */ 603 | key = HEAD2(s->b, s->bp); 604 | s->head2[key] = SWD_UINT(s->bp); 605 | #endif 606 | 607 | swd_getbyte(s); 608 | } while (--n > 0); 609 | } 610 | 611 | 612 | /*********************************************************************** 613 | // 614 | ************************************************************************/ 615 | 616 | static 617 | void swd_search(ucl_swd_t * s, ucl_uint node, ucl_uint cnt) 618 | { 619 | #if 0 && defined(__GNUC__) && defined(__i386__) 620 | register const unsigned char *p1 __asm__("%edi"); 621 | register const unsigned char *p2 __asm__("%esi"); 622 | register const unsigned char *px __asm__("%edx"); 623 | #else 624 | const unsigned char *p1; 625 | const unsigned char *p2; 626 | const unsigned char *px; 627 | #endif 628 | ucl_uint m_len = s->m_len; 629 | const unsigned char *b = s->b; 630 | const unsigned char *bp = s->b + s->bp; 631 | const unsigned char *bx = s->b + s->bp + s->look; 632 | unsigned char scan_end1; 633 | 634 | assert(s->m_len > 0); 635 | 636 | scan_end1 = bp[m_len - 1]; 637 | for (; cnt-- > 0; node = s->succ3[node]) { 638 | p1 = bp; 639 | p2 = b + node; 640 | px = bx; 641 | 642 | assert(m_len < s->look); 643 | 644 | if ( 645 | #if 1 646 | p2[m_len - 1] == scan_end1 && 647 | p2[m_len] == p1[m_len] && 648 | #endif 649 | p2[0] == p1[0] && p2[1] == p1[1]) { 650 | ucl_uint i; 651 | assert(ucl_memcmp(bp, &b[node], 3) == 0); 652 | 653 | #if 0 && defined(UCL_UNALIGNED_OK_4) 654 | p1 += 3; 655 | p2 += 3; 656 | while (p1 < px 657 | && *(const ucl_uint32p) p1 == 658 | *(const ucl_uint32p) p2) 659 | p1 += 4, p2 += 4; 660 | while (p1 < px && *p1 == *p2) 661 | p1 += 1, p2 += 1; 662 | #else 663 | p1 += 2; 664 | p2 += 2; 665 | do { 666 | } while (++p1 < px && *p1 == *++p2); 667 | #endif 668 | i = p1 - bp; 669 | 670 | #ifdef UCL_DEBUG 671 | if (ucl_memcmp(bp, &b[node], i) != 0) 672 | printf("%5ld %5ld %02x%02x %02x%02x\n", 673 | (long) s->bp, (long) node, 674 | bp[0], bp[1], b[node], b[node + 1]); 675 | #endif 676 | assert(ucl_memcmp(bp, &b[node], i) == 0); 677 | 678 | #if defined(SWD_BEST_OFF) 679 | if (i < SWD_BEST_OFF) { 680 | if (s->best_pos[i] == 0) 681 | s->best_pos[i] = node + 1; 682 | } 683 | #endif 684 | if (i > m_len) { 685 | s->m_len = m_len = i; 686 | s->m_pos = node; 687 | if (m_len == s->look) 688 | return; 689 | if (m_len >= s->nice_length) 690 | return; 691 | if (m_len > (ucl_uint) s->best3[node]) 692 | return; 693 | scan_end1 = bp[m_len - 1]; 694 | } 695 | } 696 | } 697 | } 698 | 699 | 700 | /*********************************************************************** 701 | // 702 | ************************************************************************/ 703 | 704 | #ifdef HEAD2 705 | 706 | static 707 | ucl_bool swd_search2(ucl_swd_t * s) 708 | { 709 | ucl_uint key; 710 | 711 | assert(s->look >= 2); 712 | assert(s->m_len > 0); 713 | 714 | key = s->head2[HEAD2(s->b, s->bp)]; 715 | if (key == NIL2) 716 | return 0; 717 | #ifdef UCL_DEBUG 718 | if (ucl_memcmp(&s->b[s->bp], &s->b[key], 2) != 0) 719 | printf("%5ld %5ld %02x%02x %02x%02x\n", (long) s->bp, 720 | (long) key, s->b[s->bp], s->b[s->bp + 1], s->b[key], 721 | s->b[key + 1]); 722 | #endif 723 | assert(ucl_memcmp(&s->b[s->bp], &s->b[key], 2) == 0); 724 | #if defined(SWD_BEST_OFF) 725 | if (s->best_pos[2] == 0) 726 | s->best_pos[2] = key + 1; 727 | #endif 728 | 729 | if (s->m_len < 2) { 730 | s->m_len = 2; 731 | s->m_pos = key; 732 | } 733 | return 1; 734 | } 735 | 736 | #endif 737 | 738 | 739 | /*********************************************************************** 740 | // 741 | ************************************************************************/ 742 | 743 | static 744 | void swd_findbest(ucl_swd_t * s) 745 | { 746 | ucl_uint key; 747 | ucl_uint cnt, node; 748 | ucl_uint len; 749 | 750 | assert(s->m_len > 0); 751 | 752 | /* get current head, add bp into HEAD3 */ 753 | key = HEAD3(s->b, s->bp); 754 | node = s->succ3[s->bp] = s_head3(s, key); 755 | cnt = s->llen3[key]++; 756 | assert(s->llen3[key] <= s->n + s->f); 757 | if (cnt > s->max_chain && s->max_chain > 0) 758 | cnt = s->max_chain; 759 | s->head3[key] = SWD_UINT(s->bp); 760 | 761 | s->b_char = s->b[s->bp]; 762 | len = s->m_len; 763 | if (s->m_len >= s->look) { 764 | if (s->look == 0) 765 | s->b_char = -1; 766 | s->m_off = 0; 767 | s->best3[s->bp] = SWD_UINT(s->f + 1); 768 | } else { 769 | #ifdef HEAD2 770 | if (swd_search2(s)) 771 | #endif 772 | if (s->look >= 3) 773 | swd_search(s, node, cnt); 774 | if (s->m_len > len) 775 | s->m_off = swd_pos2off(s, s->m_pos); 776 | s->best3[s->bp] = SWD_UINT(s->m_len); 777 | 778 | #if defined(SWD_BEST_OFF) 779 | if (s->use_best_off) { 780 | int i; 781 | for (i = 2; i < SWD_BEST_OFF; i++) 782 | if (s->best_pos[i] > 0) 783 | s->best_off[i] = 784 | swd_pos2off(s, 785 | s->best_pos[i] - 786 | 1); 787 | else 788 | s->best_off[i] = 0; 789 | } 790 | #endif 791 | } 792 | 793 | swd_remove_node(s, s->rp); 794 | 795 | #ifdef HEAD2 796 | /* add bp into HEAD2 */ 797 | key = HEAD2(s->b, s->bp); 798 | s->head2[key] = SWD_UINT(s->bp); 799 | #endif 800 | } 801 | 802 | 803 | #undef HEAD3 804 | #undef HEAD2 805 | #undef s_head3 806 | 807 | 808 | /*********************************************************************** 809 | // 810 | ************************************************************************/ 811 | 812 | static int 813 | init_match(UCL_COMPRESS_T * c, ucl_swd_t * s, 814 | const ucl_byte * dict, ucl_uint dict_len, ucl_uint32 flags) 815 | { 816 | int r; 817 | 818 | assert(!c->init); 819 | c->init = 1; 820 | 821 | s->c = c; 822 | 823 | c->last_m_len = c->last_m_off = 0; 824 | 825 | c->textsize = c->codesize = c->printcount = 0; 826 | c->lit_bytes = c->match_bytes = c->rep_bytes = 0; 827 | c->lazy = 0; 828 | 829 | r = swd_init(s, dict, dict_len); 830 | if (r != UCL_E_OK) { 831 | swd_exit(s); 832 | return r; 833 | } 834 | 835 | s->use_best_off = (flags & 1) ? 1 : 0; 836 | return UCL_E_OK; 837 | } 838 | 839 | 840 | /*********************************************************************** 841 | // 842 | ************************************************************************/ 843 | 844 | static int 845 | find_match(UCL_COMPRESS_T * c, ucl_swd_t * s, 846 | ucl_uint this_len, ucl_uint skip) 847 | { 848 | assert(c->init); 849 | 850 | if (skip > 0) { 851 | assert(this_len >= skip); 852 | swd_accept(s, this_len - skip); 853 | c->textsize += this_len - skip + 1; 854 | } else { 855 | assert(this_len <= 1); 856 | c->textsize += this_len - skip; 857 | } 858 | 859 | s->m_len = THRESHOLD; 860 | #ifdef SWD_BEST_OFF 861 | if (s->use_best_off) 862 | memset(s->best_pos, 0, sizeof(s->best_pos)); 863 | #endif 864 | swd_findbest(s); 865 | c->m_len = s->m_len; 866 | #if defined(__UCL_CHECKER) 867 | /* s->m_off may be uninitialized if we didn't find a match, 868 | * but then its value will never be used. 869 | */ 870 | c->m_off = (s->m_len == THRESHOLD) ? 0 : s->m_off; 871 | #else 872 | c->m_off = s->m_off; 873 | #endif 874 | 875 | swd_getbyte(s); 876 | 877 | if (s->b_char < 0) { 878 | c->look = 0; 879 | c->m_len = 0; 880 | swd_exit(s); 881 | } else { 882 | c->look = s->look + 1; 883 | } 884 | c->bp = c->ip - c->look; 885 | 886 | #if 0 887 | /* brute force match search */ 888 | if (c->m_len > THRESHOLD && c->m_len + 1 <= c->look) { 889 | const ucl_byte *ip = c->bp; 890 | const ucl_byte *m = c->bp - c->m_off; 891 | const ucl_byte *in = c->in; 892 | 893 | if (ip - in > N) 894 | in = ip - N; 895 | for (;;) { 896 | while (*in != *ip) 897 | in++; 898 | if (in == ip) 899 | break; 900 | if (in != m) 901 | if (memcmp(in, ip, c->m_len + 1) == 0) 902 | printf("%p %p %p %5d\n", in, ip, m, 903 | c->m_len); 904 | in++; 905 | } 906 | } 907 | #endif 908 | 909 | if (c->cb && c->textsize > c->printcount) { 910 | (*c->cb->callback) (c->textsize, c->codesize, 3, c->cb->user); 911 | c->printcount += 1024; 912 | } 913 | 914 | return UCL_E_OK; 915 | } 916 | 917 | 918 | /*********************************************************************** 919 | // bit buffer 920 | ************************************************************************/ 921 | 922 | static int bbConfig(UCL_COMPRESS_T * c, int endian, int bitsize) 923 | { 924 | if (endian != -1) { 925 | if (endian != 0) 926 | return UCL_E_ERROR; 927 | c->bb_c_endian = endian; 928 | } 929 | if (bitsize != -1) { 930 | if (bitsize != 8 && bitsize != 16 && bitsize != 32) 931 | return UCL_E_ERROR; 932 | c->bb_c_s = bitsize; 933 | c->bb_c_s8 = bitsize / 8; 934 | } 935 | c->bb_b = 0; 936 | c->bb_k = 0; 937 | c->bb_p = NULL; 938 | c->bb_op = NULL; 939 | return UCL_E_OK; 940 | } 941 | 942 | 943 | static void bbWriteBits(UCL_COMPRESS_T * c) 944 | { 945 | ucl_byte *p = c->bb_p; 946 | ucl_uint32 b = c->bb_b; 947 | 948 | p[0] = UCL_BYTE(b >> 0); 949 | if (c->bb_c_s >= 16) { 950 | p[1] = UCL_BYTE(b >> 8); 951 | if (c->bb_c_s == 32) { 952 | p[2] = UCL_BYTE(b >> 16); 953 | p[3] = UCL_BYTE(b >> 24); 954 | } 955 | } 956 | } 957 | 958 | 959 | static void bbPutBit(UCL_COMPRESS_T * c, unsigned bit) 960 | { 961 | assert(bit == 0 || bit == 1); 962 | assert(c->bb_k <= c->bb_c_s); 963 | 964 | if (c->bb_k < c->bb_c_s) { 965 | if (c->bb_k == 0) { 966 | assert(c->bb_p == NULL); 967 | c->bb_p = c->bb_op; 968 | c->bb_op += c->bb_c_s8; 969 | } 970 | assert(c->bb_p != NULL); 971 | assert(c->bb_p + c->bb_c_s8 <= c->bb_op); 972 | 973 | c->bb_b = (c->bb_b << 1) + bit; 974 | c->bb_k++; 975 | } else { 976 | assert(c->bb_p != NULL); 977 | assert(c->bb_p + c->bb_c_s8 <= c->bb_op); 978 | 979 | bbWriteBits(c); 980 | c->bb_p = c->bb_op; 981 | c->bb_op += c->bb_c_s8; 982 | c->bb_b = bit; 983 | c->bb_k = 1; 984 | } 985 | } 986 | 987 | 988 | static void bbPutByte(UCL_COMPRESS_T * c, unsigned b) 989 | { 990 | /**printf("putbyte %p %p %x (%d)\n", op, bb_p, x, bb_k);*/ 991 | assert(c->bb_p == NULL || c->bb_p + c->bb_c_s8 <= c->bb_op); 992 | *c->bb_op++ = UCL_BYTE(b); 993 | } 994 | 995 | 996 | static void bbFlushBits(UCL_COMPRESS_T * c, unsigned filler_bit) 997 | { 998 | if (c->bb_k > 0) { 999 | assert(c->bb_k <= c->bb_c_s); 1000 | while (c->bb_k != c->bb_c_s) 1001 | bbPutBit(c, filler_bit); 1002 | bbWriteBits(c); 1003 | c->bb_k = 0; 1004 | } 1005 | c->bb_p = NULL; 1006 | } 1007 | 1008 | 1009 | 1010 | /*********************************************************************** 1011 | // 1012 | ************************************************************************/ 1013 | 1014 | static void code_prefix_ss11(UCL_COMPRESS_T * c, ucl_uint32 i) 1015 | { 1016 | if (i >= 2) { 1017 | ucl_uint32 t = 4; 1018 | i += 2; 1019 | do { 1020 | t <<= 1; 1021 | } while (i >= t); 1022 | t >>= 1; 1023 | do { 1024 | t >>= 1; 1025 | bbPutBit(c, (i & t) ? 1 : 0); 1026 | bbPutBit(c, 0); 1027 | } while (t > 2); 1028 | } 1029 | bbPutBit(c, (unsigned) i & 1); 1030 | bbPutBit(c, 1); 1031 | } 1032 | 1033 | 1034 | #if defined(NRV2D) || defined(NRV2E) 1035 | static void code_prefix_ss12(UCL_COMPRESS_T * c, ucl_uint32 i) 1036 | { 1037 | if (i >= 2) { 1038 | ucl_uint32 t = 2; 1039 | do { 1040 | i -= t; 1041 | t <<= 2; 1042 | } while (i >= t); 1043 | do { 1044 | t >>= 1; 1045 | bbPutBit(c, (i & t) ? 1 : 0); 1046 | bbPutBit(c, 0); 1047 | t >>= 1; 1048 | bbPutBit(c, (i & t) ? 1 : 0); 1049 | } while (t > 2); 1050 | } 1051 | bbPutBit(c, (unsigned) i & 1); 1052 | bbPutBit(c, 1); 1053 | } 1054 | #endif 1055 | 1056 | 1057 | static void 1058 | code_match(UCL_COMPRESS_T * c, ucl_uint m_len, const ucl_uint m_off) 1059 | { 1060 | unsigned m_low = 0; 1061 | 1062 | while (m_len > c->conf.max_match) { 1063 | code_match(c, c->conf.max_match - 3, m_off); 1064 | m_len -= c->conf.max_match - 3; 1065 | } 1066 | 1067 | c->match_bytes += m_len; 1068 | if (m_len > c->result[3]) 1069 | c->result[3] = m_len; 1070 | if (m_off > c->result[1]) 1071 | c->result[1] = m_off; 1072 | 1073 | bbPutBit(c, 0); 1074 | 1075 | #if defined(NRV2B) 1076 | if (m_off == c->last_m_off) { 1077 | bbPutBit(c, 0); 1078 | bbPutBit(c, 1); 1079 | } else { 1080 | code_prefix_ss11(c, 1 + ((m_off - 1) >> 8)); 1081 | bbPutByte(c, (unsigned) m_off - 1); 1082 | } 1083 | m_len = m_len - 1 - (m_off > M2_MAX_OFFSET); 1084 | if (m_len >= 4) { 1085 | bbPutBit(c, 0); 1086 | bbPutBit(c, 0); 1087 | code_prefix_ss11(c, m_len - 4); 1088 | } else { 1089 | bbPutBit(c, m_len > 1); 1090 | bbPutBit(c, (unsigned) m_len & 1); 1091 | } 1092 | #elif defined(NRV2D) 1093 | m_len = m_len - 1 - (m_off > M2_MAX_OFFSET); 1094 | assert(m_len > 0); 1095 | m_low = (m_len >= 4) ? 0u : (unsigned) m_len; 1096 | if (m_off == c->last_m_off) { 1097 | bbPutBit(c, 0); 1098 | bbPutBit(c, 1); 1099 | bbPutBit(c, m_low > 1); 1100 | bbPutBit(c, m_low & 1); 1101 | } else { 1102 | code_prefix_ss12(c, 1 + ((m_off - 1) >> 7)); 1103 | bbPutByte(c, 1104 | ((((unsigned) m_off - 1) & 0x7f) << 1) | 1105 | ((m_low > 1) ? 0 : 1)); 1106 | bbPutBit(c, m_low & 1); 1107 | } 1108 | if (m_len >= 4) 1109 | code_prefix_ss11(c, m_len - 4); 1110 | #elif defined(NRV2E) 1111 | m_len = m_len - 1 - (m_off > M2_MAX_OFFSET); 1112 | assert(m_len > 0); 1113 | m_low = (m_len <= 2); 1114 | if (m_off == c->last_m_off) { 1115 | bbPutBit(c, 0); 1116 | bbPutBit(c, 1); 1117 | bbPutBit(c, m_low); 1118 | } else { 1119 | code_prefix_ss12(c, 1 + ((m_off - 1) >> 7)); 1120 | bbPutByte(c, 1121 | ((((unsigned) m_off - 1) & 0x7f) << 1) | (m_low ^ 1122 | 1)); 1123 | } 1124 | if (m_low) 1125 | bbPutBit(c, (unsigned) m_len - 1); 1126 | else if (m_len <= 4) { 1127 | bbPutBit(c, 1); 1128 | bbPutBit(c, (unsigned) m_len - 3); 1129 | } else { 1130 | bbPutBit(c, 0); 1131 | code_prefix_ss11(c, m_len - 5); 1132 | } 1133 | #else 1134 | # error 1135 | #endif 1136 | 1137 | c->last_m_off = m_off; 1138 | UCL_UNUSED(m_low); 1139 | } 1140 | 1141 | 1142 | static void code_run(UCL_COMPRESS_T * c, const ucl_byte * ii, ucl_uint lit) 1143 | { 1144 | if (lit == 0) 1145 | return; 1146 | c->lit_bytes += lit; 1147 | if (lit > c->result[5]) 1148 | c->result[5] = lit; 1149 | do { 1150 | bbPutBit(c, 1); 1151 | bbPutByte(c, *ii++); 1152 | } while (--lit > 0); 1153 | } 1154 | 1155 | 1156 | /*********************************************************************** 1157 | // 1158 | ************************************************************************/ 1159 | 1160 | static int 1161 | len_of_coded_match(UCL_COMPRESS_T * c, ucl_uint m_len, ucl_uint m_off) 1162 | { 1163 | int b; 1164 | if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET)) 1165 | || m_off > c->conf.max_offset) 1166 | return -1; 1167 | assert(m_off > 0); 1168 | 1169 | m_len = m_len - 2 - (m_off > M2_MAX_OFFSET); 1170 | 1171 | if (m_off == c->last_m_off) 1172 | b = 1 + 2; 1173 | else { 1174 | #if defined(NRV2B) 1175 | b = 1 + 10; 1176 | m_off = (m_off - 1) >> 8; 1177 | while (m_off > 0) { 1178 | b += 2; 1179 | m_off >>= 1; 1180 | } 1181 | #elif defined(NRV2D) || defined(NRV2E) 1182 | b = 1 + 9; 1183 | m_off = (m_off - 1) >> 7; 1184 | while (m_off > 0) { 1185 | b += 3; 1186 | m_off >>= 2; 1187 | } 1188 | #else 1189 | # error 1190 | #endif 1191 | } 1192 | 1193 | #if defined(NRV2B) || defined(NRV2D) 1194 | b += 2; 1195 | if (m_len < 3) 1196 | return b; 1197 | m_len -= 3; 1198 | #elif defined(NRV2E) 1199 | b += 2; 1200 | if (m_len < 2) 1201 | return b; 1202 | if (m_len < 4) 1203 | return b + 1; 1204 | m_len -= 4; 1205 | #else 1206 | # error 1207 | #endif 1208 | do { 1209 | b += 2; 1210 | m_len >>= 1; 1211 | } while (m_len > 0); 1212 | 1213 | return b; 1214 | } 1215 | 1216 | 1217 | /*********************************************************************** 1218 | // 1219 | ************************************************************************/ 1220 | 1221 | #if !defined(NDEBUG) 1222 | static 1223 | void assert_match(const ucl_swd_p swd, ucl_uint m_len, ucl_uint m_off) 1224 | { 1225 | const UCL_COMPRESS_T *c = swd->c; 1226 | ucl_uint d_off; 1227 | 1228 | assert(m_len >= 2); 1229 | if (m_off <= (ucl_uint) (c->bp - c->in)) { 1230 | assert(c->bp - m_off + m_len < c->ip); 1231 | assert(ucl_memcmp(c->bp, c->bp - m_off, m_len) == 0); 1232 | } else { 1233 | assert(swd->dict != NULL); 1234 | d_off = m_off - (ucl_uint) (c->bp - c->in); 1235 | assert(d_off <= swd->dict_len); 1236 | if (m_len > d_off) { 1237 | assert(ucl_memcmp 1238 | (c->bp, swd->dict_end - d_off, d_off) == 0); 1239 | assert(c->in + m_len - d_off < c->ip); 1240 | assert(ucl_memcmp 1241 | (c->bp + d_off, c->in, m_len - d_off) == 0); 1242 | } else { 1243 | assert(ucl_memcmp 1244 | (c->bp, swd->dict_end - d_off, m_len) == 0); 1245 | } 1246 | } 1247 | } 1248 | #else 1249 | # define assert_match(a,b,c) ((void)0) 1250 | #endif 1251 | 1252 | 1253 | #if defined(SWD_BEST_OFF) 1254 | 1255 | static void 1256 | better_match(const ucl_swd_p swd, ucl_uint * m_len, ucl_uint * m_off) 1257 | { 1258 | } 1259 | 1260 | #endif 1261 | 1262 | 1263 | /*********************************************************************** 1264 | // 1265 | ************************************************************************/ 1266 | 1267 | UCL_PUBLIC(int) 1268 | ucl_nrv_99_compress(const ucl_bytep in, ucl_uint in_len, 1269 | ucl_bytep out, ucl_uintp out_len, 1270 | ucl_progress_callback_p cb, 1271 | int level, 1272 | const struct ucl_compress_config_p conf, 1273 | ucl_uintp result) 1274 | { 1275 | const ucl_byte *ii; 1276 | ucl_uint lit; 1277 | ucl_uint m_len, m_off; 1278 | UCL_COMPRESS_T c_buffer; 1279 | UCL_COMPRESS_T *const c = &c_buffer; 1280 | #undef swd 1281 | #if 1 && defined(SWD_USE_MALLOC) 1282 | ucl_swd_t the_swd; 1283 | # define swd (&the_swd) 1284 | #else 1285 | ucl_swd_p swd; 1286 | #endif 1287 | ucl_uint result_buffer[16]; 1288 | int r; 1289 | 1290 | struct swd_config_t { 1291 | unsigned try_lazy; 1292 | ucl_uint good_length; 1293 | ucl_uint max_lazy; 1294 | ucl_uint nice_length; 1295 | ucl_uint max_chain; 1296 | ucl_uint32 flags; 1297 | ucl_uint32 max_offset; 1298 | }; 1299 | const struct swd_config_t *sc; 1300 | static const struct swd_config_t swd_config[10] = { 1301 | /* faster compression */ 1302 | {0, 0, 0, 8, 4, 0, 48 * 1024L}, 1303 | {0, 0, 0, 16, 8, 0, 48 * 1024L}, 1304 | {0, 0, 0, 32, 16, 0, 48 * 1024L}, 1305 | {1, 4, 4, 16, 16, 0, 48 * 1024L}, 1306 | {1, 8, 16, 32, 32, 0, 48 * 1024L}, 1307 | {1, 8, 16, 128, 128, 0, 48 * 1024L}, 1308 | {2, 8, 32, 128, 256, 0, 128 * 1024L}, 1309 | {2, 32, 128, F, 2048, 1, 128 * 1024L}, 1310 | {2, 32, 128, F, 2048, 1, 256 * 1024L}, 1311 | {2, F, F, F, 4096, 1, N} 1312 | /* max. compression */ 1313 | }; 1314 | 1315 | if (level < 1 || level > 10) 1316 | return UCL_E_INVALID_ARGUMENT; 1317 | sc = &swd_config[level - 1]; 1318 | 1319 | memset(c, 0, sizeof(*c)); 1320 | c->ip = c->in = in; 1321 | c->in_end = in + in_len; 1322 | c->out = out; 1323 | if (cb && cb->callback) 1324 | c->cb = cb; 1325 | cb = NULL; 1326 | c->result = result ? result : (ucl_uintp) result_buffer; 1327 | memset(c->result, 0, 16 * sizeof(*c->result)); 1328 | c->result[0] = c->result[2] = c->result[4] = UCL_UINT_MAX; 1329 | result = NULL; 1330 | memset(&c->conf, 0xff, sizeof(c->conf)); 1331 | if (conf) 1332 | memcpy(&c->conf, conf, sizeof(c->conf)); 1333 | conf = NULL; 1334 | r = bbConfig(c, 0, 8); 1335 | if (r == 0) 1336 | r = bbConfig(c, c->conf.bb_endian, c->conf.bb_size); 1337 | if (r != 0) 1338 | return UCL_E_INVALID_ARGUMENT; 1339 | c->bb_op = out; 1340 | 1341 | ii = c->ip; /* point to start of literal run */ 1342 | lit = 0; 1343 | 1344 | #if !defined(swd) 1345 | swd = (ucl_swd_p) ucl_alloc(1, ucl_sizeof(*swd)); 1346 | if (!swd) 1347 | return UCL_E_OUT_OF_MEMORY; 1348 | #endif 1349 | swd->f = UCL_MIN(F, c->conf.max_match); 1350 | swd->n = UCL_MIN(N, sc->max_offset); 1351 | if (c->conf.max_offset != UCL_UINT_MAX) 1352 | swd->n = UCL_MIN(N, c->conf.max_offset); 1353 | if (in_len >= 256 && in_len < swd->n) 1354 | swd->n = in_len; 1355 | if (swd->f < 8 || swd->n < 256) 1356 | return UCL_E_INVALID_ARGUMENT; 1357 | r = init_match(c, swd, NULL, 0, sc->flags); 1358 | if (r != UCL_E_OK) { 1359 | #if !defined(swd) 1360 | ucl_free(swd); 1361 | #endif 1362 | return r; 1363 | } 1364 | if (sc->max_chain > 0) 1365 | swd->max_chain = sc->max_chain; 1366 | if (sc->nice_length > 0) 1367 | swd->nice_length = sc->nice_length; 1368 | if (c->conf.max_match < swd->nice_length) 1369 | swd->nice_length = c->conf.max_match; 1370 | 1371 | if (c->cb) 1372 | (*c->cb->callback) (0, 0, -1, c->cb->user); 1373 | 1374 | c->last_m_off = 1; 1375 | r = find_match(c, swd, 0, 0); 1376 | if (r != UCL_E_OK) 1377 | return r; 1378 | while (c->look > 0) { 1379 | ucl_uint ahead; 1380 | ucl_uint max_ahead; 1381 | int l1, l2; 1382 | 1383 | c->codesize = c->bb_op - out; 1384 | 1385 | m_len = c->m_len; 1386 | m_off = c->m_off; 1387 | 1388 | assert(c->bp == c->ip - c->look); 1389 | assert(c->bp >= in); 1390 | if (lit == 0) 1391 | ii = c->bp; 1392 | assert(ii + lit == c->bp); 1393 | assert(swd->b_char == *(c->bp)); 1394 | 1395 | if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET)) 1396 | || m_off > c->conf.max_offset) { 1397 | /* a literal */ 1398 | lit++; 1399 | swd->max_chain = sc->max_chain; 1400 | r = find_match(c, swd, 1, 0); 1401 | assert(r == 0); 1402 | continue; 1403 | } 1404 | 1405 | /* a match */ 1406 | #if defined(SWD_BEST_OFF) 1407 | if (swd->use_best_off) 1408 | better_match(swd, &m_len, &m_off); 1409 | #endif 1410 | assert_match(swd, m_len, m_off); 1411 | 1412 | /* shall we try a lazy match ? */ 1413 | ahead = 0; 1414 | if (sc->try_lazy <= 0 || m_len >= sc->max_lazy 1415 | || m_off == c->last_m_off) { 1416 | /* no */ 1417 | l1 = 0; 1418 | max_ahead = 0; 1419 | } else { 1420 | /* yes, try a lazy match */ 1421 | l1 = len_of_coded_match(c, m_len, m_off); 1422 | assert(l1 > 0); 1423 | max_ahead = UCL_MIN(sc->try_lazy, m_len - 1); 1424 | } 1425 | 1426 | while (ahead < max_ahead && c->look > m_len) { 1427 | if (m_len >= sc->good_length) 1428 | swd->max_chain = sc->max_chain >> 2; 1429 | else 1430 | swd->max_chain = sc->max_chain; 1431 | r = find_match(c, swd, 1, 0); 1432 | ahead++; 1433 | 1434 | assert(r == 0); 1435 | assert(c->look > 0); 1436 | assert(ii + lit + ahead == c->bp); 1437 | 1438 | if (c->m_len < 2) 1439 | continue; 1440 | #if defined(SWD_BEST_OFF) 1441 | if (swd->use_best_off) 1442 | better_match(swd, &c->m_len, &c->m_off); 1443 | #endif 1444 | l2 = len_of_coded_match(c, c->m_len, c->m_off); 1445 | if (l2 < 0) 1446 | continue; 1447 | #if 1 1448 | if (l1 + (int) (ahead + c->m_len - m_len) * 5 > 1449 | l2 + (int) (ahead) * 9) 1450 | #else 1451 | if (l1 > l2) 1452 | #endif 1453 | { 1454 | c->lazy++; 1455 | assert_match(swd, c->m_len, c->m_off); 1456 | 1457 | #if 0 1458 | if (l3 > 0) { 1459 | /* code previous run */ 1460 | code_run(c, ii, lit); 1461 | lit = 0; 1462 | /* code shortened match */ 1463 | code_match(c, ahead, m_off); 1464 | } else 1465 | #endif 1466 | { 1467 | lit += ahead; 1468 | assert(ii + lit == c->bp); 1469 | } 1470 | goto lazy_match_done; 1471 | } 1472 | } 1473 | 1474 | assert(ii + lit + ahead == c->bp); 1475 | 1476 | /* 1 - code run */ 1477 | code_run(c, ii, lit); 1478 | lit = 0; 1479 | 1480 | /* 2 - code match */ 1481 | code_match(c, m_len, m_off); 1482 | swd->max_chain = sc->max_chain; 1483 | r = find_match(c, swd, m_len, 1 + ahead); 1484 | assert(r == 0); 1485 | 1486 | lazy_match_done:; 1487 | } 1488 | 1489 | /* store final run */ 1490 | code_run(c, ii, lit); 1491 | 1492 | /* EOF */ 1493 | bbPutBit(c, 0); 1494 | #if defined(NRV2B) 1495 | code_prefix_ss11(c, UCL_UINT32_C(0x1000000)); 1496 | bbPutByte(c, 0xff); 1497 | #elif defined(NRV2D) || defined(NRV2E) 1498 | code_prefix_ss12(c, UCL_UINT32_C(0x1000000)); 1499 | bbPutByte(c, 0xff); 1500 | #else 1501 | # error 1502 | #endif 1503 | bbFlushBits(c, 0); 1504 | 1505 | assert(c->textsize == in_len); 1506 | c->codesize = c->bb_op - out; 1507 | *out_len = c->bb_op - out; 1508 | if (c->cb) 1509 | (*c->cb->callback) (c->textsize, c->codesize, 4, c->cb->user); 1510 | 1511 | #if 0 1512 | printf("%7ld %7ld -> %7ld %7ld %7ld %ld (max: %d %d %d)\n", 1513 | (long) c->textsize, (long) in_len, (long) c->codesize, 1514 | c->match_bytes, c->lit_bytes, c->lazy, 1515 | c->result[1], c->result[3], c->result[5]); 1516 | #endif 1517 | assert(c->lit_bytes + c->match_bytes == in_len); 1518 | 1519 | swd_exit(swd); 1520 | #if !defined(swd) 1521 | ucl_free(swd); 1522 | #endif 1523 | return UCL_E_OK; 1524 | #undef swd 1525 | } 1526 | 1527 | 1528 | /* 1529 | vi:ts=4:et 1530 | */ 1531 | -------------------------------------------------------------------------------- /src/poly.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: poly.c, kinda lame polymorphic engine 3 | * 4 | * The decryptor will look like 5 | * 6 | * 0: mov $key1, %reg1 \ 7 | * 1: mov $key2, %reg2 \ these may be randomly exchanged 8 | * 2: mov $length, %reg3 / 9 | * 3: mov $addr, %reg4 / 10 | * 11 | * 4: xor %reg1, (%reg4) 12 | * 5: sub %reg2, (%reg4) \ exchangable 13 | * 6: add %reg2, %reg1 / 14 | * 7: lea x(%reg4), %reg4 / add x, %reg4 \ exchangable 15 | * 8: lea x(%reg4), %reg4 / add x, %reg4 / 16 | * 9: dec %reg3 17 | * jz loopout 18 | * 19 | * 20 | * each instruction statement has before and after some one-byte junk 21 | * (cli, nop ..), following a jump to randomly placed next statement, 22 | * a`la Onehalf. 23 | * 24 | * virii folks will know -- kinda lame ;p 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "elfuck.h" 34 | #include "poly.h" 35 | 36 | typedef struct { 37 | int pos; 38 | int len; 39 | } poly_state; 40 | 41 | static void blewgap(unsigned char **p) 42 | { 43 | int gaplen = (rand() % (MAXGAPLEN-MINGAPLEN)) + MINGAPLEN; 44 | unsigned char *buf = *p; 45 | (*p) += gaplen; 46 | while (gaplen--) 47 | #ifdef NOPGAP 48 | *buf++ = 0x90; 49 | #else 50 | *buf++ = rand() & 0xff; 51 | #endif 52 | } 53 | 54 | static int freeregs[3]; 55 | 56 | static void blewnop(unsigned char **p) 57 | { 58 | unsigned char *b = *p; 59 | static char tab[] = "\xf8\xfc\xf5\xf9\xfd\x90"; 60 | (*p)++; 61 | switch (rand() % 3) { 62 | case 0: /* dec */ 63 | *b = 0x48 + freeregs[rand() % 3]; 64 | break; 65 | case 1: /* inc */ 66 | *b = 0x40 + freeregs[rand() % 3]; 67 | break; 68 | case 2: /* some one-byte */ 69 | *b = tab[rand() % (sizeof(tab)-1)]; 70 | break; 71 | } 72 | } 73 | 74 | static void blewnops(unsigned char **p) { 75 | int i = (rand() % MAXJUNK)+1; 76 | while (i--) { 77 | blewnop(p); 78 | } 79 | } 80 | 81 | static void blewadd(unsigned char **p, unsigned num, int reg) 82 | { 83 | unsigned char *buf = *p; 84 | switch (rand() % 3) { 85 | /* classic add */ 86 | case 0: 87 | buf[0] = 0x81; 88 | buf[1] = 0xc0 + reg; 89 | *((unsigned *)(&buf[2])) = num; 90 | break; 91 | /* sub -number */ 92 | case 1: 93 | buf[0] = 0x81; 94 | buf[1] = 0xe8 + reg; 95 | *((unsigned *)(&buf[2])) = 0-num; 96 | break; 97 | /* lea num(%reg), reg */ 98 | case 2: 99 | buf[0] = 0x8d; 100 | buf[1] = 0x80 + reg + reg*8; 101 | *((unsigned *)(&buf[2])) = num; 102 | break; 103 | } 104 | (*p) += 6; 105 | } 106 | 107 | void mix_jump(int *tab, int count) 108 | { 109 | int i, j, k, s; 110 | for (i = 0; i < count*count; i++) { 111 | j = rand() % count; 112 | k = (j+1) % count; 113 | s = tab[j]; 114 | tab[j] = tab[k]; 115 | tab[k] = s; 116 | } 117 | } 118 | 119 | char *poly_gen(poly_key *key) 120 | { 121 | poly_state st[10]; 122 | unsigned char *ret, *before, *outjump = NULL; 123 | unsigned char *p = ret = malloc((MAXGAPLEN+64)*10); 124 | int regs[4]; 125 | int ii, i, j, k; 126 | unsigned koef1, koef2; 127 | int jtab[10]; 128 | 129 | memset(st, 0, sizeof(st)); 130 | memset(regs, 0, sizeof(regs)); 131 | 132 | /* generate keys */ 133 | srand(time(NULL)); 134 | key->a = rand() ^ (rand() << 16); 135 | key->b = rand() ^ (rand() << 16); 136 | koef1 = rand() ^ (rand() << 16); 137 | koef2 = (0-koef1) + 4; 138 | 139 | /* generate registers */ 140 | for (i = 0; i < 4; i++) { 141 | int a; 142 | a = (rand() % 8)-1; 143 | again: 144 | a = (a+1) % 8; 145 | if (a == 4) goto again; 146 | for (j = 0; j < i; j++) { 147 | if (regs[j] == a) 148 | goto again; 149 | } 150 | regs[i] = a; 151 | } 152 | 153 | /* pick the rest */ 154 | for (i = 0, k = 0; i < 8; i++) { 155 | if (i == 4) continue; 156 | for (j = 0; j < 4; j++) { 157 | if (i == regs[j]) 158 | goto next; 159 | } 160 | for (j = 0; j < k; j++) { 161 | if (i == freeregs[j]) 162 | goto next; 163 | } 164 | freeregs[k++] = i; 165 | next: 166 | ; 167 | } 168 | 169 | for (ii = 0; ii < 10; ii++) { 170 | int state; 171 | 172 | /* introduce us by real shit ;p */ 173 | blewgap(&p); 174 | 175 | /* find free state */ 176 | for (state = rand() % 10; st[state].len; state = (state+1) % 10); 177 | 178 | 179 | /* put few nops */ 180 | before = p; 181 | blewnops(&p); 182 | switch (state) { 183 | case 0: 184 | *p++ = 0xb8 + regs[0]; 185 | *((ulong *) p) = key->a; 186 | p += 4; 187 | break; 188 | case 1: 189 | *p++ = 0xb8 + regs[1]; 190 | *((ulong *) p) = key->b; 191 | p += 4; 192 | break; 193 | case 2: 194 | *p++ = 0xb8 + regs[2]; 195 | key->plen = p-ret; 196 | p += 4; 197 | break; 198 | case 3: 199 | *p++ = 0xb8 + regs[3]; 200 | key->paddr = p-ret; 201 | p += 4; 202 | break; 203 | case 4: 204 | *p++ = 0x31; 205 | *p++ = 0x40 + regs[3] + regs[0] * 8; 206 | *p++ = 0; 207 | break; 208 | case 5: 209 | *p++ = 0x29; 210 | *p++ = 0x40 + regs[3] + regs[1] * 8; 211 | *p++ = 0; 212 | break; 213 | case 6: 214 | *p++ = 1; 215 | *p++ = 0xc0 + regs[0] + regs[1] * 8; 216 | break; 217 | case 7: 218 | blewadd(&p, koef1, regs[3]); 219 | break; 220 | case 8: 221 | blewadd(&p, koef2, regs[3]); 222 | break; 223 | case 9: 224 | *p++ = 0x48 + regs[2]; 225 | outjump = p; 226 | /* space for jump code */ 227 | for (i = 0; i < 6; i++) 228 | blewnop(&p); 229 | break; 230 | } 231 | blewnops(&p); 232 | st[state].pos = before - ret; 233 | st[state].len = p - before; 234 | } 235 | /* ok, we have our states */ 236 | blewgap(&p); 237 | 238 | /* now compute jumps */ 239 | for (i = 0; i < 9; i++) { 240 | jtab[i] = i+1; 241 | } 242 | jtab[9] = 4; 243 | 244 | /* XXX-TODO: Not implemented yet 245 | mix_jump(&jtab[0], 4); 246 | mix_jump(&jtab[5], 2); 247 | mix_jump(&jtab[7], 2); */ 248 | 249 | key->start = st[0].pos; 250 | 251 | /* place jump instruction after each label */ 252 | for (i = 0; i < 10; i++) { 253 | long from = st[i].pos + st[i].len; 254 | long to = st[jtab[i]].pos; 255 | long rel = to-from-2; 256 | if ((rel > 127) || (rel < -127)) { 257 | /* near jump */ 258 | ret[from] = 0xe9; 259 | *((long *)(&ret[from+1])) = rel-3; 260 | } else { 261 | /* short jump */ 262 | ret[from] = 0xeb; 263 | ret[from+1] = ((unsigned long) rel) & 0xff; 264 | } 265 | } 266 | 267 | /* and finally, setup the jump-out instruction */ 268 | i = p-outjump-2; 269 | if (i > 127) { 270 | /* near 'jz' */ 271 | outjump[0] = 0x0f; 272 | outjump[1] = 0x84; 273 | *((long *)(&outjump[2])) = i-4; 274 | } else { 275 | /* short 'jz' */ 276 | outjump[0] = 0x74; 277 | outjump[1] = i; 278 | } 279 | key->len = p-ret; 280 | return ret; 281 | } 282 | 283 | void poly_encrypt(unsigned char *data, int len, poly_key *key) 284 | { 285 | unsigned *p = (void *) data; 286 | unsigned a,b; 287 | 288 | len = (len+3) >> 2; 289 | a = key->a; 290 | b = key->b; 291 | 292 | while (len--) { 293 | *p += b; 294 | *p ^= a; 295 | a += b; 296 | p++; 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /src/stubify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: stubify.c, well, this is what actually screws up any ELF file. 3 | * 4 | * Produced SFX executable looks like: 5 | * 6 | * 7 | * 8 | * 9 | * 120 decompressor [entrypoint] 10 | * 4 ptr to dest (needed by decompressor) 11 | * x1 packed elf body 12 | * 4096-x2 13 | * x2 ELF loader <-- from this point decompressor stores output 14 | * ---- there begins original ELF base 15 | * two segments of original elf, merged to one 16 | */ 17 | 18 | /* you can put anything there */ 19 | #define PWDPROMPT "password:" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "nrv2e.h" 30 | #include "elfuck.h" 31 | #include "decompress.h" 32 | #include "execelf.h" 33 | #include "stubify.h" 34 | #include "poly.h" 35 | #include "getpw.h" 36 | #include "lock.h" 37 | 38 | static int olen; 39 | void pack_callback(int ts, int cs, void *d) 40 | { 41 | static int c = 0; 42 | register int k = ts * 100 / olen; 43 | 44 | if (c != k) { 45 | fprintf(stderr, "\r%d %%", k); 46 | c = k; 47 | } 48 | } 49 | 50 | #define OFFSET(x) ((x) & 4095) 51 | int stubify_elf(uchar *src, uchar *dest, int size, int level, int flags) 52 | { 53 | struct elf32_hdr *e = (void *) src; 54 | struct stub *o = (void *) dest; 55 | struct elf32_phdr *p; 56 | ulong lo = -1, hi = 0, memhi = 0, start = 0; 57 | uchar *pa, *ka; 58 | int i, d = 0; 59 | ucl_callback cb; 60 | struct elf_aux *aux; 61 | int bsize = sizeof(ELF_BANNER)-1, esize = EXECELF_SIZE + 1; 62 | int have_interp = 0; 63 | poly_key pk; 64 | uchar *poly = NULL; 65 | uchar phash[20]; 66 | ulong testhash[5]; 67 | int lsize = 0; 68 | uchar *lock = NULL; 69 | 70 | if (strncmp(e->e_ident, "\177ELF", 4)) { 71 | eprintf("ERROR: Input file not in ELF format\n"); 72 | return -1; 73 | } 74 | 75 | memset(&pk, 0, sizeof(pk)); 76 | 77 | if (flags & FLAG_NOBANNER) 78 | bsize = 0; 79 | 80 | if (flags & FLAG_SCRAMBLE) { 81 | poly = poly_gen(&pk); 82 | } 83 | 84 | if (flags & FLAG_LOCK) { 85 | int lp = sizeof(PWDPROMPT)-1; 86 | int lpn = -lp; 87 | getpassw(phash); 88 | lock = malloc(LOCK_SIZE + lp + sizeof(lpn)); 89 | memcpy(lock + LOCK_SIZE, PWDPROMPT, lp); 90 | memcpy(lock + LOCK_SIZE + lp, &lpn, sizeof(lpn)); 91 | lsize = LOCK_SIZE + lp + sizeof(lpn); 92 | } 93 | 94 | /* find code and data segments */ 95 | for (i = 0, p = (void *) (src + e->e_phoff); i < e->e_phnum; i++, p++) { 96 | if (p->p_type == PT_LOAD) { 97 | if (p->p_vaddr < lo) lo = p->p_vaddr; 98 | if ((p->p_vaddr+p->p_filesz) > hi) 99 | hi = p->p_vaddr + p->p_filesz; 100 | if ((p->p_vaddr+p->p_memsz) > memhi) 101 | memhi = p->p_vaddr + p->p_memsz; 102 | } 103 | if (p->p_type == PT_INTERP) { 104 | strcpy(execelf_interp, src + p->p_offset); 105 | esize += strlen(execelf_interp); 106 | have_interp = 1; 107 | } 108 | } 109 | 110 | if (!have_interp) { 111 | /* huh. this is really hackish, ELF haven't interpreter, 112 | so zero interpreter loader code for better compression, 113 | as it will be never used anyway */ 114 | memset(e_skip_interp, 0, e_no_interp-e_skip_interp); 115 | } 116 | 117 | lo = ALIGNDOWN(lo); 118 | hi = ALIGNUP(hi); 119 | memhi = ALIGNUP(memhi); 120 | printf("size in file: %ld, size in memory: %ld\n", hi-lo, memhi-lo); 121 | 122 | /* allocate source buffer we'll be compressing */ 123 | ka = pa = malloc((hi-lo) + esize); 124 | if (!pa) { 125 | perror("ERROR: malloc failed"); 126 | return -1; 127 | } 128 | memcpy(ka, execelf, esize); pa += esize; 129 | memset(pa, 0, (hi-lo)); 130 | 131 | /* copy file data to it */ 132 | for (i = 0, p = (void *) (src + e->e_phoff); i < e->e_phnum; i++, p++) { 133 | if (p->p_type == PT_LOAD) { 134 | memcpy( pa + ALIGNDOWN(p->p_vaddr - lo), 135 | src + p->p_offset - OFFSET(p->p_vaddr), 136 | p->p_filesz + OFFSET(p->p_vaddr)); 137 | memcpy( pa + p->p_vaddr - lo, 138 | src + p->p_offset, 139 | p->p_filesz); 140 | } 141 | } 142 | 143 | /* ok, now compress that sucker */ 144 | printf("Compressing ...\n"); 145 | cb.callback = (void *) pack_callback; 146 | olen = (hi-lo) + esize; 147 | d = bsize + DECOMPRESS_SIZE + pk.len + lsize; 148 | ucl_nrv2e_99_compress(ka, olen, o->data + d, &i, &cb, level, NULL, NULL); 149 | aux = (void *) (o->data + d + i); 150 | i += sizeof(*aux); 151 | 152 | start = ALIGNDOWN(lo - (sizeof(struct stub) + d + i + 4096)); 153 | if (start > 0x7fffffff) { 154 | printf("FATAL: There is not enough space for us!\n"); 155 | free(ka); 156 | return -1; 157 | } 158 | 159 | /* ok, it's time to setup headers */ 160 | memcpy(o->elf.e_ident, "\177ELF", 4); 161 | o->elf.e_type = ET_EXEC; 162 | o->elf.e_machine = EM_386; 163 | o->elf.e_version = 1; 164 | o->elf.e_entry = start + bsize + sizeof(o->elf) + sizeof(o->phdr); 165 | o->elf.e_phoff = sizeof(o->elf); 166 | o->elf.e_shoff = o->elf.e_flags = 0; 167 | o->elf.e_ehsize = sizeof(o->elf); 168 | o->elf.e_phentsize = sizeof(o->phdr); 169 | o->elf.e_phnum = 1; 170 | o->elf.e_shentsize = o->elf.e_shnum = o->elf.e_shstrndx = 0; 171 | 172 | /* we'have only one segment */ 173 | o->phdr.p_type = PT_LOAD; 174 | o->phdr.p_offset = 0; 175 | o->phdr.p_vaddr = o->phdr.p_paddr = start; 176 | o->phdr.p_filesz = sizeof(o->elf) + sizeof(o->phdr) + d + i; 177 | o->phdr.p_memsz = memhi - start; 178 | o->phdr.p_flags = PF_R | PF_W | PF_X; 179 | o->phdr.p_align = 4096; 180 | 181 | /* copy the decompressor */ 182 | memcpy(o->data, ELF_BANNER, bsize); 183 | decompress_src = o->elf.e_entry + pk.len + lsize + DECOMPRESS_SIZE - 4; 184 | decompress_dest = lo - esize; 185 | memcpy(o->data + bsize + pk.len + lsize, decompress, DECOMPRESS_SIZE); 186 | 187 | /* setup aux variables for execelf */ 188 | aux->phdr = e->e_phoff + lo; 189 | aux->phnum = e->e_phnum; 190 | aux->entry = e->e_entry; 191 | aux->freestart = start; 192 | aux->freelen = lo - start - 4096; 193 | 194 | /* lock the result if requiered */ 195 | if (lock) { 196 | uchar *data = o->data + bsize + pk.len + lsize; 197 | int llen = (DECOMPRESS_SIZE + i); 198 | sha1_asm((char *) testhash, data, llen); 199 | lock_testkey = testhash[0]; 200 | lock_start = o->elf.e_entry + pk.len + lsize; 201 | locked_len = llen; 202 | memcpy(lock, elf_lock, LOCK_SIZE); 203 | memcpy(o->data + bsize + pk.len, lock, lsize); 204 | rc4_asm(phash, data, llen); 205 | } 206 | 207 | /* scramble the result if requiered */ 208 | if (pk.len) { 209 | ulong slen = (DECOMPRESS_SIZE + i + lsize); 210 | poly_encrypt(o->data + bsize + pk.len, 211 | slen, &pk); 212 | 213 | /* setup the descrambler */ 214 | *((ulong *)(&poly[pk.plen])) = (slen+3) >> 2; 215 | *((ulong *)(&poly[pk.paddr])) = o->elf.e_entry + pk.len; 216 | o->elf.e_entry += pk.start; 217 | 218 | /* and copy the polymorphic descrambler */ 219 | memcpy(o->data + bsize, poly, pk.len); 220 | } 221 | 222 | free(ka); 223 | free(poly); 224 | free(lock); 225 | return o->phdr.p_filesz; 226 | } 227 | 228 | /* this will pack arbitrary ELF in 'src' to 'dest' with 'evel' */ 229 | int pack_elf(char *src, char *dest, int level, int flags) 230 | { 231 | int in, out, size, t; 232 | uchar *i, *o; 233 | 234 | printf("Packing%s%s%s '%s' to '%s'\n", 235 | flags & FLAG_SCRAMBLE ? ", scrambling" : "", 236 | flags & FLAG_LOCK ? ", locking" : "", 237 | flags & FLAG_NOBANNER ? " without banner" : "", 238 | src, dest); 239 | 240 | /* open input/output streams */ 241 | in = open(src, O_RDONLY); 242 | if (in < 0) { 243 | perror(src); 244 | return 1; 245 | } 246 | 247 | out = open(dest, O_CREAT | O_RDWR | O_TRUNC, 0744); 248 | if (out < 0) { 249 | perror(dest); 250 | return 1; 251 | } 252 | 253 | size = lseek(in, 0, SEEK_END); 254 | ftruncate(out, ALIGNDOWN(size*2) + 4096); 255 | 256 | /* mmap them */ 257 | i = mmap(NULL, ALIGNUP(size), PROT_READ, MAP_SHARED, in, 0); 258 | if (i == MAP_FAILED) { 259 | perror("mmap"); 260 | close(in); close(out); 261 | return 1; 262 | } 263 | 264 | o = mmap(NULL, ALIGNDOWN(size*2) + 4096, PROT_READ | PROT_WRITE, MAP_SHARED, 265 | out, 0); 266 | if (o == MAP_FAILED) { 267 | perror("mmap"); 268 | close(in); close(out); munmap(i, ALIGNUP(size)); 269 | return 1; 270 | } 271 | t = stubify_elf(i, o, size, level, flags); 272 | munmap(i, ALIGNUP(size)); 273 | munmap(o, ALIGNDOWN(size*2) + 4096); 274 | if (t >= 0) { 275 | printf("\rOk, compressed to %.2f%% (%d => %d)\n", t * 100.0 / size, size, t); 276 | ftruncate(out, t); 277 | close(out); 278 | } else { 279 | printf("\rCompression failed!\n"); 280 | close(out); 281 | unlink(dest); 282 | } 283 | close(in); 284 | return t<0?-1:0; 285 | } 286 | --------------------------------------------------------------------------------