Strengthening Diversification Defenses by Means of a Non-Readable Code

Total Page:16

File Type:pdf, Size:1020Kb

Strengthening Diversification Defenses by Means of a Non-Readable Code 1 Strengthening diversification defenses by means of a non-readable code segment Sebastian Österlund Department of Computer Science Vrije Universiteit, Amsterdam, Netherlands Supervised By: H. Bos & C. Giuffrida Abstract—In this paper we present a new defense against Just- hardware segmentation, this approach should theoretically have In-Time return-oriented-programming attacks. By making pro- no run-time performance overhead for Intel x86 architecture, gram code non-readable, the assembly of Just-In-Time gadgets by once it has been set up. Both position dependent executables scanning the memory is effectively blocked. Using segmentation and position independent executables are covered. Furthermore on Intel x86 hardware, the implementation of execute-only code an approach to implement a similar defense on x86_64 using can be achieved. We discuss two different ways of implementing the new MPX [7] instructions is presented. The defense such a defense for 32-bit Intel architecture: one for position dependent executables, and one for position independent executa- mechanism we present in this paper is of interest, mainly, bles. The first implementation works by splitting the address- for use in security of network connected applications (such space into two mirrored segments. The second implementation as servers or web-browsers), since these applications are often creates an execute-only memory-section at the top of the address- the main targets of remote code execution exploits. space, making it possible to still use the whole address-space. By relying on hardware segmentation the run-time performance II. RETURN-ORIENTED-PROGRAMMING ATTACKS overhead of these defenses is minimal. Remote code execution by means of buffer overflows has Keywords—ROP, segmentation, XnR, buffer overflow, memory been a problem for a long time. In this section we give an disclosure. overview of such remote code execution exploits. By overwriting a function return address, code at an arbitrary I. INTRODUCTION location can be executed, thereby making remote code exe- cution possible. The following code demonstrates a common In recent years traditional remote code execution exploits, exploitable bug in programs: making use of buffer-overflows, have become obsolete due to the introduction of data execution prevention (DEP) tech- void vulnerable_function( char ∗ user_input) niques. Techniques such as Intel NX [1] enforce a policy { of making writable data non-executable. On the other hand, char buffer[12]; attacks such as return-to-libc and other Return-Oriented- strcpy(buffer , user_input); Programming attacks overcome such techniques by executing } (snippets of) existing code which necessarily has to be exe- cutable [2], creating a so-called gadget chain. An overview of void hacked ( ) how these attacks work will be given in Sec. II. { A common defense against ROP-exploits is Address-space p r i n t f ( " I have been hacked!!!!"); layout randomization (ASLR). ASLR mitigates many of these } attacks by randomizing the layout of a program loaded in memory. However, there are several known weaknesses in the i n t main ( i n t argc , char ∗ argv [ ] ) currently used ASLR implementations [3]. { For example a leaked pointer disclosure may give away vulnerable_function(argv[1]); the base-address of executable code (e.g. the base address of return 0 ; libc), thus making it possible to simply add an offset in the } pre-assembled gadget chain. Fine-grained ASLR makes this In the example above, the length of the string user_input is harder [4][5], since the code is split up into smaller blocks unknown. Since strcpy copies characters until it reaches a end- and shuffled around. It has however been shown in [6] that, of-string character (i.e. NULL) 1, the program may overwrite thanks to memory disclosure vulnerabilities, these gadgets can memory beyond the buffer. be assembled for a specific target by scanning the memory Using this buffer overflow, an attacker may overwrite the for code snippets. By creating such a just-in-time assembled return address of the function vulnerable_function. By pointing exploit, the defense provided by ASLR is circumvented. The contribution made by this paper is a segmentation-based 1Some compilers actually do object-size checking on strcpy, preventing defense against memory disclosure attacks. By relying on some common buffer-overflows. 2 ... point in a procedure) in the return address. Usually this would not be critical, since the existing code in a program is limited attacker inserted value return address in scope. However, an attacker may also choose to execute code from a library, giving the attacker much more available vulnerable_function() Local variables executable code to work with. It is possible to chain together library functions by putting char *buffer the address of the next function in the return address of the called function. By assembling such a chain, a so-called gadget main() chain is created. Furthermore, it has been shown in [2] that the GNU C library is Turing complete, thus any arbitrary program ... can be constructed by chaining together functions from libc. Fig. 1: Example of buffer overflow attack. strcpy overwrites III. NON-READABLE CODE the return address by an address entered by the attacker, When gadget chains are assembled, the memory is scanned executing code at a location chosen by the attacker. for pieces of executable code that can be "glued" together. For example an attacker may scan the memory for a POP- instruction followed by a return. By scanning the memory for such gadgets, a very targeted attack can be assembled this address to another function the execution of the program Just-in-time, without knowing the exact location of executable may be altered (See Fig. 2). Furthermore, an attacker may put code. If it, however, was prohibited to scan the memory, these arbitrary code into memory and point the return address to the attacks would be rendered useless. By enforcing a policy entered code. of making executable code non-readable (the abbreviation Luckily, data execution prevention techniques such as W ⊕ XnR will henceforth be used for this primitive) it becomes X2, making executable data non-writable, prohibit the exe- impossible to scan the memory for such gadgets. XnR together cution of malicious code entered in this manner. When the with ASLR, would make it very hard (or rather impossible) processor tries to execute data on a page that is marked NX to determine where certain snippets of code are located, thus (non-executable) the processor throws an exception, terminat- creating a strong defense against JIT-ROP attacks. ing the offending program. Sadly, implementing such a policy is not achieved by just marking executable pages non-readable. For Intel x86, memory ... that is executable implies that it is readable, thus XnR has to be implemented in another way. The obvious approach would arg to system() Fill in: /bin/sh be to emulate execute-only functionality on a per-page basis in software. Such an implementation is presented in [8] and return address of system() will be discussed further in Sec. IX. In short: the problem with this approach is that software emulation adds some overhead, address of libc system() function return address which is not necessarily required. In the next section a novel approach of achieving non-readable text without software- vulnerable_function() Local variables based page access emulation is presented. char *buffer IV. SEGMENTATION-BASED ACCESS POLICY main() A. Segmentation on Intel x86 For the 8086 processor, Intel introduced segmentation. This ... memory-translation feature allows memory to be split into separate disjoint logical entities called segments. Segmentation Fig. 2: Example return-to-libc attack. If the process runs as allows programmers to create programs consisting of multiple root, an attacker may gain access to a shell with root privileges. segments located at different addresses in physical memory, When the command system("/bin/sh") is executed the attacker without having to worry about at which address in physical has gained root access to the system. memory certain parts of a program is loaded. The historical idea behind segmentation was to allow programmers to split the program into logically structured separated parts. There Despite this protection it is still possible for an attacker to are, thus, two kinds of segment types: data and code. Data execute existing code. Since program code necessarily needs segments can only be used for reading/ writing memory, while to be executable (why else call it a program...), it is possible code segments allow the memory-contents to be executed. For to execute existing functions by placing its address (or any a more comprehensive description of segmentation see chapter 3.7 of [9]. 2Introduced by OpenBSD in 2003 (http://marc.info/?l=openbsd- When a valid segment descriptor has been loaded into a miscm=105056000801065) segment register, all access to memory is relative to the base 3 C. Loading text in a separate segment Fig. 3: The layout of a standard ELF program in Linux with a flat address-space. The Code Segment (CS) and Data The main idea behind protection we propose is quite novel: Segment(DS) both cover the same area, namely 0x00000000 load text into an address outside the limits of the user data - 0xffffffff segment, but inside a new code segment. When a read is performed on an address outside the user data segment, the ... processor will throw a protection fault, while allowing an stack instruction fetch from that same address. A problem with splitting the memory in two segments is that compilers and linkers for Linux assume a flat memory model. When the Kernel loads the code, it assumes one contiguous mmap region piece of memory, where the access policy is determined by the page handler. Thus care should be given to load the correct Code Segment (CS) Data Segment (DS) section at the right memory address.
Recommended publications
  • Theendokernel: Fast, Secure
    The Endokernel: Fast, Secure, and Programmable Subprocess Virtualization Bumjin Im Fangfei Yang Chia-Che Tsai Michael LeMay Rice University Rice University Texas A&M University Intel Labs Anjo Vahldiek-Oberwagner Nathan Dautenhahn Intel Labs Rice University Abstract Intra-Process Sandbox Multi-Process Commodity applications contain more and more combina- ld/st tions of interacting components (user, application, library, and Process Process Trusted Unsafe system) and exhibit increasingly diverse tradeoffs between iso- Unsafe ld/st lation, performance, and programmability. We argue that the Unsafe challenge of future runtime isolation is best met by embracing syscall()ld/st the multi-principle nature of applications, rethinking process Trusted Trusted read/ architecture for fast and extensible intra-process isolation. We IPC IPC write present, the Endokernel, a new process model and security Operating System architecture that nests an extensible monitor into the standard process for building efficient least-authority abstractions. The Endokernel introduces a new virtual machine abstraction for Figure 1: Problem: intra-process is bypassable because do- representing subprocess authority, which is enforced by an main is opaque to OS, sandbox limits functionality, and inter- efficient self-isolating monitor that maps the abstraction to process is slow and costly to apply. Red indicates limitations. system level objects (processes, threads, files, and signals). We show how the Endokernel Architecture can be used to develop enforces subprocess access control to memory and CPU specialized separation abstractions using an exokernel-like state [10, 17, 24, 25, 75].Unfortunately, these approaches only organization to provide virtual privilege rings, which we use virtualize minimal parts of the CPU and neglect tying their to reorganize and secure NGINX.
    [Show full text]
  • Memory Layout and Access Chapter Four
    Memory Layout and Access Chapter Four Chapter One discussed the basic format for data in memory. Chapter Three covered how a computer system physically organizes that data. This chapter discusses how the 80x86 CPUs access data in memory. 4.0 Chapter Overview This chapter forms an important bridge between sections one and two (Machine Organization and Basic Assembly Language, respectively). From the point of view of machine organization, this chapter discusses memory addressing, memory organization, CPU addressing modes, and data representation in memory. From the assembly language programming point of view, this chapter discusses the 80x86 register sets, the 80x86 mem- ory addressing modes, and composite data types. This is a pivotal chapter. If you do not understand the material in this chapter, you will have difficulty understanding the chap- ters that follow. Therefore, you should study this chapter carefully before proceeding. This chapter begins by discussing the registers on the 80x86 processors. These proces- sors provide a set of general purpose registers, segment registers, and some special pur- pose registers. Certain members of the family provide additional registers, although typical application do not use them. After presenting the registers, this chapter describes memory organization and seg- mentation on the 80x86. Segmentation is a difficult concept to many beginning 80x86 assembly language programmers. Indeed, this text tends to avoid using segmented addressing throughout the introductory chapters. Nevertheless, segmentation is a power- ful concept that you must become comfortable with if you intend to write non-trivial 80x86 programs. 80x86 memory addressing modes are, perhaps, the most important topic in this chap- ter.
    [Show full text]
  • DOS Virtualized in the Linux Kernel
    DOS Virtualized in the Linux Kernel Robert T. Johnson, III Abstract Due to the heavy dominance of Microsoft Windows® in the desktop market, some members of the software industry believe that new operating systems must be able to run Windows® applications to compete in the marketplace. However, running applications not native to the operating system generally causes their performance to degrade significantly. When the application and the operating system were written to run on the same machine architecture, all of the instructions in the application can still be directly executed under the new operating system. Some will only need to be interpreted differently to provide the required functionality. This paper investigates the feasibility and potential to speed up the performance of such applications by including the support needed to run them directly in the kernel. In order to avoid the impact to the kernel when these applications are not running, the needed support was built as a loadable kernel module. 1 Introduction New operating systems face significant challenges in gaining consumer acceptance in the desktop marketplace. One of the first realizations that must be made is that the majority of this market consists of non-technical users who are unlikely to either understand or have the desire to understand various technical details about why the new operating system is “better” than a competitor’s. This means that such details are extremely unlikely to sway a large amount of users towards the operating system by themselves. The incentive for a consumer to continue using their existing operating system or only upgrade to one that is backwards compatible is also very strong due to the importance of application software.
    [Show full text]
  • Chapter 3 Protected-Mode Memory Management
    CHAPTER 3 PROTECTED-MODE MEMORY MANAGEMENT This chapter describes the Intel 64 and IA-32 architecture’s protected-mode memory management facilities, including the physical memory requirements, segmentation mechanism, and paging mechanism. See also: Chapter 5, “Protection” (for a description of the processor’s protection mechanism) and Chapter 20, “8086 Emulation” (for a description of memory addressing protection in real-address and virtual-8086 modes). 3.1 MEMORY MANAGEMENT OVERVIEW The memory management facilities of the IA-32 architecture are divided into two parts: segmentation and paging. Segmentation provides a mechanism of isolating individual code, data, and stack modules so that multiple programs (or tasks) can run on the same processor without interfering with one another. Paging provides a mech- anism for implementing a conventional demand-paged, virtual-memory system where sections of a program’s execution environment are mapped into physical memory as needed. Paging can also be used to provide isolation between multiple tasks. When operating in protected mode, some form of segmentation must be used. There is no mode bit to disable segmentation. The use of paging, however, is optional. These two mechanisms (segmentation and paging) can be configured to support simple single-program (or single- task) systems, multitasking systems, or multiple-processor systems that used shared memory. As shown in Figure 3-1, segmentation provides a mechanism for dividing the processor’s addressable memory space (called the linear address space) into smaller protected address spaces called segments. Segments can be used to hold the code, data, and stack for a program or to hold system data structures (such as a TSS or LDT).
    [Show full text]
  • MP Assignment V.Pages
    MP Assignment V 1. A. With a neat diagram, explain the internal structure of Pentium Pro. The Pentium Pro is structured d i f f e r e n t l y t h a n e a r l i e r microprocessors. The system buses, which communicate to the memory and I/O, connect to an internal level 2 cache that is often on the main board in most other microprocessor systems. The level 2 cache in the Pentium Pro is either 256K bytes or 512K bytes. The bus interface unit (BIU) controls the access to the system buses through the level 2 cache, which is integrated in Pentium Pro. The BIU generates the memory address and control signals, and passes and fetches data or instructions to either a level 1 data cache or a level 1 instruction cache. The instruction cache is connected to the instruction fetch and decode unit (IFDU). Pentium Pro can process two integer instructions and one floating-point instruction simultaneously. The dispatch and execute unit (DEU) retrieves decoded instructions from the instruction pool when they are complete, and then executes them. Pentium Pro has a RU (Retire unit) which checks the instruction pool and removes decoded instructions that have been executed. B. List the new features added to Pentium Pro when compared with its predecessors with respect to memory system. The memory system for the Pentium Pro microprocessor is 4G bytes in size, similar to 80386DX–Pentium microprocessors, but access to an area between 4G and 64G is made possible by additional address signals A32-35.
    [Show full text]
  • Motorola DSP56000 Family Optimizing C Compiler User’S Manual Motorola
    Freescale Semiconductor, Inc. Motorola DSP56000 Family nc... Optimizing C Compiler User’s Manual, Release 6.3 DSP56KCCUM/D Document Rev. 2.0, 07/1999 Freescale Semiconductor, I For More Information On This Product, Go to: www.freescale.com Freescale Semiconductor, Inc. nc... Suite56, OnCe, and MFAX are trademarks of Motorola, Inc. Motorola reserves the right to make changes without further notice to any products herein. Motorola makes no warranty, representation or guarantee regarding the suitability of its products for any particular purpose, nor does Motorola assume any liability arising out of the application or use of any product or circuit, and specifically disclaims any and all liability, including without limitation consequential or incidental damages. “Typical” parameters which may be provided in Motorola data sheets and/or specifications can and do vary in different applications and actual performance may vary over time. All operating parameters, including “Typicals” must be validated for each customer application by customer’s technical experts. Motorola does not convey any license under its patent rights nor the rights of others. Motorola products are not designed, intended, or authorized for use as components in systems intended for surgical implant into the body, or other applications intended to support life, or for any other application in Freescale Semiconductor, I which the failure of the Motorola product could create a situation where personal injury or death may occur. Should Buyer purchase or use Motorola products for any such unintended or unauthorized application, Buyer shall indemnify and hold Motorola and its officers, employees, subsidiaries, affiliates, and distributors harmless against all claims, costs, damages, and expenses, and reasonable attorney fees arising out of, directly or indirectly, any claim of personal injury or death associated with such unintended or unauthorized use, even if such claim alleges that Motorola was negligent regarding the design or manufacture of the part.
    [Show full text]
  • IA-32 Architecture
    Outline IA-32 Architecture Intel Microprocessors IA-32 Registers Computer Organization Instruction Execution Cycle & IA-32 Memory Management Assembly Language Programming Dr Adnan Gutub aagutub ‘at’ uqu.edu.sa [Adapted from slides of Dr. Kip Irvine: Assembly Language for Intel-Based Computers] Most Slides contents have been arranged by Dr Muhamed Mudawar & Dr Aiman El-Maleh from Computer Engineering Dept. at KFUPM 45/٢ IA-32 Architecture Computer Organization and Assembly Language slide Intel Microprocessors Intel 80286 and 80386 Processors Intel introduced the 8086 microprocessor in 1979 80286 was introduced in 1982 8086, 8087, 8088, and 80186 processors 24-bit address bus ⇒ 224 bytes = 16 MB address space 16-bit processors with 16-bit registers Introduced protected mode 16-bit data bus and 20-bit address bus Segmentation in protected mode is different from the real mode Physical address space = 220 bytes = 1 MB 80386 was introduced in 1985 8087 Floating-Point co-processor First 32-bit processor with 32-bit general-purpose registers Uses segmentation and real-address mode to address memory First processor to define the IA-32 architecture Each segment can address 216 bytes = 64 KB 32-bit data bus and 32-bit address bus 8088 is a less expensive version of 8086 232 bytes ⇒ 4 GB address space Uses an 8-bit data bus Introduced paging , virtual memory , and the flat memory model 80186 is a faster version of 8086 Segmentation can be turned off 45/٤ 45 IA-32 Architecture Computer Organization and Assembly Language slide/٣
    [Show full text]
  • Assembly Language
    Chapter 2 Instructions: Assembly Language Reading: The corresponding chapter in the 2nd edition is Chapter 3, in the 3rd edition it is Chapter 2 and Appendix A and in the 4th edition it is Chapter 2 and Appendix B. 2.1 Instructions and Instruction set The language to command a computer architecture is comprised of instructions and the vocabulary of that language is called the instruction set. The only way computers can rep- resent information is based on high or low electric signals, i.e., transistors (electric switches) being turned on or off. Being limited to those 2 alternatives, we represent information in com- puters using bits (binary digits), which can have one of two values: 0 or 1. So, instructions will be stored in and read by computers as sequences of bits. This is called machine language. To make sure we don't need to read and write programs using bits, every instruction will also have a "natural language" equivalent, called the assembly language notation. For example, in C, we can use the expression c = a + b; or, in assembly language, we can use add c; a; b and these instructions will be represented by a sequence of bits 000000 010001001 in the computer. Groups of bits are named as follows: ··· bit 0 or 1 byte 8 bits half word 16 bits word 32 bits double word 64 bits Since every bit can only be 0 or 1, with a group of n bits, we can generate 2n different combinations of bits. For example, we can make 28 combinations with one byte (8 bits), 216 with one half word (16 bits), and 232 with one word (32 bits).
    [Show full text]
  • Outline Executable/Object File Formats Brief History of Binary File Formats
    Outline CSci 5980/8980 ELF basics Manual and Automated Binary Reverse Engineering Slides 5: The ELF Binary File Format Stephen McCamant Static and dynamic linking University of Minnesota Executable/object file formats Brief history of binary file formats (Unix) Modern systems usually use a common format for Early Unix had a simple a.out format relocatable object files during compilation and final Lasted until early days of free Linux/BSD, now obsolete executables AT&T’s second try was named COFF Mostly binary data representing code and data Still limited, but widely adopted with changes Plus metadata allowing the data to be linked and AT&T’s third try was ELF, now used in almost all Unix loaded systems Brief history of binary file formats (non-Unix) Compile-time and run-time Early DOS and Windows had several limited formats Some file features are used during compilation Since the 32-bit era, Windows uses the PE (Portable Typically first created by assembler, then used/modified Executable) format by the linker Partially derived from COFF Other features are used when the program runs OS X era Apple (including iOS, etc) uses a format By the OS when the program starts named Mach-O And now also by runtime linking First developed for the Mach microkernel used on the NeXT Static and dynamic/shared linking ELF Traditional “static” linking happens all at compile time Executable (or Extensible) and Linking (or Linkable) Libraries become indistinguishable from the rest of the Format program First appeared in System V Release 4 Unix, c. 1989 For efficiency and flexibility, it is now more common to postpone library linking until runtime Linux switched to ELF c.
    [Show full text]
  • Pentium ® Pro Family Developer's Manual
    Pentium Pro Family Developer’s Manual Volume 3: Operating System Writer’s Guide NOTE: The Pentium Pro Family Developer’s Manual consists of three books: Pentium Pro Family Developer’s Manual, Volume 1: Specifications (Order Number 242690); Pentium Pro Family Developer’s Manual, Volume 2: Programmer’s Reference Manual (Order Number 242691); and the Pentium Pro Family Developer’s Manual, Volume 3: Operating System Writer’s Guide (Order Number 242692). Please refer to all three volumes when evaluating your design needs. December 1995 Information in this document is provided in connection with Intel products. No license, express or implied, by estoppel or otherwise, to any intellectual property rights is granted by this document. Except as provided in Intel’s Terms and Conditions of Sale for such products, Intel assumes no liability whatsoever, and Intel disclaims any express or implied warranty, relating to sale and/or use of Intel products including liability or warranties relating to fitness for a particular purpose, merchantability, or infringement of any patent, copyright or other intellectual property right. Intel products are not intended for use in medical, life saving, or life sustaining applications. Intel may make changes to specifications and product descriptions at any time, without notice. The Pentium® Pro processor may contain design defects or errors known as errata. Current characterized errata are available on request. *Third-party brands and names are the property of their respective owners. Contact your local Intel sales office or your distributor to obtain the latest specifications and before placing your product order. Copies of documents which have an ordering number and are referenced in this document, or other Intel literature, may be obtained from: Intel Corporation P.O.
    [Show full text]
  • RTEMS CPU Supplement Documentation Release 4.11.2 ©Copyright 2016, RTEMS Project (Built 10Th July 2017)
    RTEMS CPU Supplement Documentation Release 4.11.2 ©Copyright 2016, RTEMS Project (built 10th July 2017) CONTENTS I RTEMS CPU Architecture Supplement1 1 Preface 3 2 Port Specific Information5 2.1 CPU Model Dependent Features...........................6 2.1.1 CPU Model Name...............................6 2.1.2 Floating Point Unit..............................6 2.2 Multilibs........................................8 2.3 Calling Conventions..................................9 2.3.1 Calling Mechanism..............................9 2.3.2 Register Usage.................................9 2.3.3 Parameter Passing...............................9 2.3.4 User-Provided Routines............................9 2.4 Memory Model..................................... 10 2.4.1 Flat Memory Model.............................. 10 2.5 Interrupt Processing.................................. 11 2.5.1 Vectoring of an Interrupt Handler...................... 11 2.5.2 Interrupt Levels................................ 11 2.5.3 Disabling of Interrupts by RTEMS...................... 12 2.6 Default Fatal Error Processing............................. 13 2.7 Symmetric Multiprocessing.............................. 14 2.8 Thread-Local Storage................................. 15 2.9 CPU counter...................................... 16 2.10 Interrupt Profiling................................... 17 2.11 Board Support Packages................................ 18 2.11.1 System Reset................................. 18 3 ARM Specific Information 19 3.1 CPU Model Dependent Features..........................
    [Show full text]
  • CPU Architecture Chapter Four
    CPU Architecture Chapter Four 4.1 Chapter Overview This chapter discusses history of the 80x86 CPU family and the major improvements occuring along the line. The historical background will help you better understand the design compromises they made as well as under- stand the legacy issues surrounding the CPU s design. This chapter also discusses the major advances in com- puter architecture that Intel employed while improving the x861. 4.2 The History of the 80x86 CPU Family Intel developed and delivered the first commercially viable microprocessor way back in the early 1970 s: the 4004 and 4040 devices. These four-bit microprocessors, intended for use in calculators, had very little power. Nevertheless, they demonstrated the future potential of the microprocessor — an entire CPU on a single piece of silicon2. Intel rapidly followed their four-bit offerings with their 8008 and 8080 eight-bit CPUs. A small outfit in Santa Fe, New Mexico, incorporated the 8080 CPU into a box they called the Altair 8800. Although this was not the world s first "personal computer" (there were some limited distribution machines built around the 8008 prior to this), the Altair was the device that sparked the imaginations of hobbyists the world over and the personal computer revolution was born. Intel soon had competition from Motorola, MOS Technology, and an upstart company formed by disgrunt- eled Intel employees, Zilog. To compete, Intel produced the 8085 microprocessor. To the software engineer, the 8085 was essentially the same as the 8080. However, the 8085 had lots of hardware improvements that made it easier to design into a circuit.
    [Show full text]