Full Download Foundations of ARM64 Linux Debugging, Disassembling, and Reversing: Analyze Code, Understand Stack Memory Usage, and Reconstruct Original C/C++ Code with ARM64 1st Edition Dmitry Vostokov PDF DOCX
Full Download Foundations of ARM64 Linux Debugging, Disassembling, and Reversing: Analyze Code, Understand Stack Memory Usage, and Reconstruct Original C/C++ Code with ARM64 1st Edition Dmitry Vostokov PDF DOCX
com
OR CLICK HERE
DOWLOAD NOW
https://ebookmass.com/product/foundations-of-arm64-linux-debugging-
disassembling-and-reversing-dmitry-vostokov/
ebookmass.com
https://ebookmass.com/product/physiology-sixth-edition-costanzo/
ebookmass.com
Business Communication: A Problem Solving Approach 1st
Edition, (Ebook PDF)
https://ebookmass.com/product/business-communication-a-problem-
solving-approach-1st-edition-ebook-pdf/
ebookmass.com
https://ebookmass.com/product/what-if-you-me-roni-loren/
ebookmass.com
https://ebookmass.com/product/interplanetary-liberty-building-free-
societies-in-the-cosmos-charles-s-cockell/
ebookmass.com
https://ebookmass.com/product/why-privacy-matters-neil-richards/
ebookmass.com
https://ebookmass.com/product/u-is-for-uncrossing-the-a-b-cs-of-
witchery-moonbeam-chronicles-book-21-carolina-mac/
ebookmass.com
Foundations of ARM64
Linux Debugging,
Disassembling, and
Reversing
Analyze Code, Understand Stack
Memory Usage, and Reconstruct
Original C/C++ Code with ARM64
—
Dmitry Vostokov
Foundations of
ARM64 Linux
Debugging,
Disassembling, and
Reversing
Analyze Code, Understand
Stack Memory Usage,
and Reconstruct Original C/C++
Code with ARM64
Dmitry Vostokov
Foundations of ARM64 Linux Debugging, Disassembling, and Reversing:
Analyze Code, Understand Stack Memory Usage, and Reconstruct Original
C/C++ Code with ARM64
Dmitry Vostokov
Dublin, Ireland
Preface����������������������������������������������������������������������������������������������xiii
iii
Table of Contents
Chapter 4: Pointers�����������������������������������������������������������������������������35
A Definition���������������������������������������������������������������������������������������������������������35
“Pointers” Project: Memory Layout and Registers����������������������������������������������36
“Pointers” Project: Calculations��������������������������������������������������������������������������38
Using Pointers to Assign Numbers to Memory Cells�������������������������������������������39
Adding Numbers Using Pointers�������������������������������������������������������������������������46
Incrementing Numbers Using Pointers���������������������������������������������������������������51
Multiplying Numbers Using Pointers�������������������������������������������������������������������54
Summary������������������������������������������������������������������������������������������������������������58
iv
Table of Contents
v
Table of Contents
vi
Table of Contents
vii
Table of Contents
Index�������������������������������������������������������������������������������������������������167
viii
About the Author
Dmitry Vostokov is an internationally
recognized expert, speaker, educator, scientist,
and author. He is the founder of the pattern-
oriented software diagnostics, forensics,
and prognostics discipline and Software
Diagnostics Institute (DA+TA: DumpAnalysis.
org + TraceAnalysis.org). Vostokov has also
authored more than 50 books on software
diagnostics, anomaly detection and analysis,
software and memory forensics, root cause analysis and problem solving,
memory dump analysis, debugging, software trace and log analysis,
reverse engineering, and malware analysis. He has more than 25 years
of experience in software architecture, design, development, and
maintenance in various industries, including leadership, technical, and
people management roles. Dmitry also founded Syndromatix, Anolog.
io, BriteTrace, DiaThings, Logtellect, OpenTask Iterative and Incremental
Publishing (OpenTask.com), Software Diagnostics Technology and
Services (former Memory Dump Analysis Services; PatternDiagnostics.
com), and Software Prognostics. In his spare time, he presents various
topics on Debugging TV and explores Software Narratology, its further
development as Narratology of Things and Diagnostics of Things (DoT),
Software Pathology, and Quantum Software Diagnostics. His current
areas of interest are theoretical software diagnostics and its mathematical
and computer science foundations, application of formal logic, artificial
intelligence, machine learning and data mining to diagnostics and anomaly
detection, software diagnostics engineering and diagnostics-driven
ix
About the Author
x
About the Technical Reviewer
Sundar Pandian has more than three
years of experience in embedded software
development, including development of device
drivers, middleware software, and application
services for the infotainment system on the
Android platform. He’s also developed CAN
protocol drivers for the automotive braking
system on the Autosar platform.
He’s developed software with C, C++,
and Java and worked in the automotive,
semiconductor, and telecom industries. He has
a bachelor’s in electronics and communication engineering. Currently, he
serves as a firmware/middleware engineer for audio DSPs.
xi
Preface
The book covers topics ranging from ARM64 assembly language
instructions and writing programs in assembly language to pointers, live
debugging, and static binary analysis of compiled C and C++ code.
Diagnostics of core memory dumps, live and postmortem debugging
of Linux applications, services, and systems, memory forensics, malware,
and vulnerability analysis require an understanding of ARM64 assembly
language and how C and C++ compilers generate code, including
memory layout and pointers. This book is about background knowledge
and practical foundations that are needed to understand internal Linux
program structure and behavior, start working with the GDB debugger, and
use it for disassembly and reversing. It consists of practical step-by-step
exercises of increasing complexity with explanations and many diagrams,
including some necessary background topics.
By the end of the book, you will have a solid understanding of how
Linux C and C++ compilers generate binary code. In addition, you will be
able to analyze such code confidently, understand stack memory usage,
and reconstruct original C/C++ code.
The book will be useful for
• Software testers
xiii
Preface
This book can also be used as an ARM64 assembly language and Linux
debugging supplement for relevant undergraduate-level courses.
Source Code
All source code used in this book can be downloaded from github.com/
apress/arm64-linux-debugging-disassembling-reversing.
xiv
CHAPTER 1
Memory, Registers,
and Simple Arithmetic
emory and Registers Inside an
M
Idealized Computer
Computer memory consists of a sequence of memory cells, and each cell
has a unique address (location). Every cell contains a “number.” We refer
to these “numbers” as contents at addresses (locations). Because memory
access is slower than arithmetic instructions, there are so-called registers
to speed up complex operations that require memory to store temporary
results. We can also think about them as stand-alone memory cells. The
name of a register is its address. Figure 1-1 illustrates this.
2
Chapter 1 Memory, Registers, and Simple Arithmetic
3
Chapter 1 Memory, Registers, and Simple Arithmetic
static int a, b;
4
Chapter 1 Memory, Registers, and Simple Arithmetic
5
Chapter 1 Memory, Registers, and Simple Arithmetic
If we use the C or C++ language, “a” is called “the variable a,” and we
write the assignment as
a = 1;
adr x0, a
mov w1, #1
str w1, [x0]
adrp x0, 0x4b2000
add x0, x0, #0xb00
mov w1, #0x1
str w1, [x0]
adrp x0, 0x4b2000, and subsequent add x0, x0, #0xb00 is how the
compiler generates code to calculate the address “a” instead of specifying it
directly. Such code is required for addressing large regions of memory, and
6
Chapter 1 Memory, Registers, and Simple Arithmetic
the compiler uses it even for smaller regions where just one adr instruction
is sufficient.
Literal constants have the # prefix, for example, #0x1. The 0x prefix
means the following number is hexadecimal. We explain such numbers
in Chapter 3. Please also notice that the movement direction is the same
in both the disassembly output and the pseudo-code: from right to left
(except for the str instruction).
After executing the first three assembly language instructions, we have
the memory layout shown in Figure 1-4A.
Figure 1-4A. Memory layout after executing the first three assembly
language instructions
7
Chapter 1 Memory, Registers, and Simple Arithmetic
Figure 1-4B. Memory layout after executing the next three assembly
language instructions
register <- 1
register <- [a]
8
Chapter 1 Memory, Registers, and Simple Arithmetic
In the GDB disassembly output, we may see the output where one
adr instruction is replaced by adrp/add instructions with parts of the
address value:
9
Chapter 1 Memory, Registers, and Simple Arithmetic
b = b + a;
b += a;
adr x0, b
ldr w1, [x0]
adr x0, a
ldr w0, [x0]
add w1, w1, w0
adr x0, b
str w1, [x0]
10
Chapter 1 Memory, Registers, and Simple Arithmetic
After executing ADR, LDR, ADD, and STR instructions, we have the
memory layout illustrated in Figure 1-5.
11
Chapter 1 Memory, Registers, and Simple Arithmetic
Figure 1-5. Memory layout after executing ADR, LDR, ADD, and STR
instructions
Incrementing/Decrementing Numbers
in Memory and Registers
In pseudo-code, it looks simple and means increment (decrement) a
number stored at the location (address) “a”:
In the C or C++ language, we can write this using three possible ways:
12
Chapter 1 Memory, Registers, and Simple Arithmetic
a = a + 1;
++a;
a++;
b = b – 1;
--b;
b--;
add x0, x0, #1
sub x0, x0, #1
adr x0, a
ldr w1, [x0]
add w1, w1, #1
str w1, [x0]
adr x0, b
ldr w1, [x0]
sub w1, w1, #1
str w1, [x0]
13
Chapter 1 Memory, Registers, and Simple Arithmetic
After the execution of the ADD instruction, we have the memory layout
illustrated in Figure 1-6.
14
Chapter 1 Memory, Registers, and Simple Arithmetic
Figure 1-6. Memory layout after the execution of the ADD instruction
Multiplying Numbers
In pseudo-code, we write
b = b * a;
b *= a;
15
Chapter 1 Memory, Registers, and Simple Arithmetic
adr x0, b
ldr w1, [x0]
adr x0, a
ldr w0, [x0]
mul w1, w1, w0
adr x0, b
str w1, [x0]
16
Chapter 1 Memory, Registers, and Simple Arithmetic
After the execution of the STR instruction, we have the memory layout
illustrated in Figure 1-7.
17
Chapter 1 Memory, Registers, and Simple Arithmetic
Figure 1-7. Memory layout after the execution of the STR instruction
Summary
This chapter introduced CPU registers and explained the memory layout
of a simple arithmetic program. We learned basic ARM64 commands,
including loading values from and storing values in memory. We also
manually translated C and C++ code to assembly language.
The next chapter looks at assembly language code produced by a
debugger via disassembling binary code. Then, we reverse it to C and C++
code. We also compare the disassembly output of nonoptimized code to
optimized code.
18
CHAPTER 2
Code Optimization
“Arithmetic” Project: C/C++ Program
Let's rewrite our “Arithmetic” program in C/C++. Corresponding assembly
language instructions are put in comments:
int a, b;
++a; // adr x0, a
// ldr w1, [x0]
// add w1, w1, #1
// str w1, [x0]
Downloading GDB
We used one of the free ARM64 Linux compute instances available from
cloud providers. In our case, GDB was already available after provisioning.
If, in your case, GDB is not available, you need to install it together with
basic build tools. For example, in Debian:
20
Chapter 2 Code Optimization
github.com/apress/arm64-linux-debugging-disassembling-
reversing/Chapter2/
we get the binary executable module we can load in GDB and inspect
assembly code.
First, we run GDB with the program as a parameter:
$ gdb ./ArithmeticProjectC
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.0.2.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/
licenses/gpl.html>
This is free software: you are free to change and
redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type
"show copying"
and "show warranty" for details.
This GDB was configured as "aarch64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
21
Chapter 2 Code Optimization
Then we start the execution of the program (let it run). The program
then stops at the previously set breakpoint:
22
Chapter 2 Code Optimization
23
Chapter 2 Code Optimization
24
Chapter 2 Code Optimization
25
Chapter 2 Code Optimization
(gdb) q
A debugging session is active.
Quit anyway? (y or n) y
$
26
Random documents with unrelated
content Scribd suggests to you:
The Project Gutenberg eBook of Second census
This ebook is for the use of anyone anywhere in the United States
and most other parts of the world at no cost and with almost no
restrictions whatsoever. You may copy it, give it away or re-use it
under the terms of the Project Gutenberg License included with this
ebook or online at www.gutenberg.org. If you are not located in the
United States, you will have to check the laws of the country where
you are located before using this eBook.
Language: English
Illustrated by SCHOENHERR
I turned back and picked up the papers he'd dropped. There was a
little sheaf of them, printed on incredibly thin paper. The printing
resembled the wave-forms I had seen upon the 'scope. It was like
some twisted Arabic script. And this strange script was overprinted on
a star-chart which I thought I recognized.
I plumbed my mind, I had it! In a star identification course at M. I. T.
they had given us star-charts showing us the galaxy as seen from
another star which we were asked to identify. One of those charts at
M. I. T. had been almost exactly the same as this: the galaxy as
viewed from Alpha Centauri!
I was stunned. I staggered a bit as I went back out on the stoop and
looked down the street. I welcomed the sight of Ed Fitzgerald
hurrying up across the neighbors' forelawns, uprooting some of the
burbanked tropical plants en route.
By the time Fitzgerald reached me, the census taker had come out of
Mike Kozulak's like a fission-freed neutron, staggered a few times in
an orbit around one of Mike's greenhouse-shelled shrubs, and
actually streaked across the two vacant lots between Mike's and
Manny Cohen's.
"He's not human," I said to Ed. "Not Earth-human. I'll swear he's from
Alpha Centauri; look at these papers! What he's after Heaven knows,
but maybe we can find out. It's a cinch he'll eventually reach Maitland
Browne's. Let's get there fast; maybe we'll be able to trap him!"
I dragged Fitzgerald inside and we went up the passenger shaft
under optimum ascent.
My little Ponticopter's jets seared the roof garden as I blasted forward
before the vanes had lifted us clear of the stage. I think I out-Browned
Browne in going those five blocks and I know I laid the foundation for
a Mrs. Browne vs. Mr. Rainford feud as I dropped my 'copter with
dismaying results into the roof garden which was her idea of Eden. I
had to, though; Brownie's is a one-copter stage and his ship was on
it.
We beat the alien. We looked back down the hill before we entered
Brownie's passenger shaft. The fellow was just staggering out of Jack
Wohl's rancher at the lower end of this last block.
We found Browne working on a stripped-down stereo chassis which
had been carelessly laid without protective padding in the middle of
the highly polished dining table. I knew then that his wife couldn't
possibly be home.
Browne looked up as if he were accustomed to unannounced people
dropping into his reception chute.
"To what do I owe the honor of—" he started. Fitzgerald interrupted
him with a stammered burst that brought a pleased grin to his broad
features.
"Well, Fitz," Browne said. "Where's the old control?"
Fitzgerald fumed. I took over and explained swiftly.
"Well, this is a problem," Browne said thoughtfully. "Now why in the
world—"
His front door chimed and became one-way transparent. We saw the
alien standing on the stoop, erect and calm.
"Now what will—" Fitzgerald started. "We thought maybe—the chair,
Brownie!"
Browne grinned and pressed a button on the table console. He has
them in every room—to control at his whim any of the dozens of
electronic and mechanical equipments located throughout his
enormous house.
The front door opened and the alien entered as Browne cried "Come
in!"
Browne flicked over a switch marked Lock 1st Fl as he rose and went
into the living room. We followed him warily.
The alien glanced back at the closed door with a trace of annoyance
on his broad features; then regarded us imperturbably as we
advanced.
"Mr. Fitzgerald and Mr. Rainford," he said flatly. "Well, this is a
surprise!"
He didn't sound sincere.
"Have a seat," Browne said, waving a big hand toward the chair.
The alien shook his head negatively.
Browne gave Fitzgerald and me a quick glance, inclining his head
forward. We promptly accelerated our advance.
"Look," Browne said, his dark face intense, "we know you're not what
you pretend to be. We know you're not of our country, not of our
world, not even of our solar system. Sit down in that chair!"
He lunged forward, grasping with his big hands, as we leaped at the
alien from either flank.
The alien didn't just move—he streaked, shooting between Browne
and Fitzgerald, heading unerringly toward the open passenger shaft
—into it!
Browne leaped to a console and punched the roof-lock button. A split
second later we heard a riveting machine burst of what was obviously
Centaurian profanity coming down the shaft as the alien found the
exit closed. Browne's fingers darted on the console, locking all the
upstairs windows.
"Browne," I said, "what good will that do? If we do manage to corner
him, just how long do you think we can stand up against him? With
his speed he could evade us until doomsday, to say nothing about
beating our brains out while we tried to land one, solid punch!"
Fitzgerald said, "If we can keep him on the run, maybe he'll get tired."
"Yeah, maybe," I said. "What if that's his normal speed? And who's
likely to get tired first? I'm dragging as of now."
"Well," Fitzgerald said, "we could get more people in and go at him in
shifts—or, well, what about tear gas or an anesthetic gas or—"
"Now, wait!" Browne snapped, unquestionably seizing command. "I'll
admit I started him on the run just now. Perhaps it was the wrong
approach. After all, he's done nothing wrong as far as we know. I—I
guess all of us—leaped to the illogical conclusion that he's out for no
good just because he's an alien. Sure, he's after something or he
wouldn't be going from door to door posing as a census taker. The
way you talk, Jim, would seem to indicate you're not curious. Well, I
am, and I'm going to do everything in my power to find out what he's
after.
"We've got to make him tell us. We can't deduce anything from the
data we have now. Sure, we know he has what you, Jim, say look like
bona fide credentials from the Census Bureau, but we also have right
here I. D. papers or something which show he's apparently from
Alpha Centauri. We know he speaks our language perfectly; ergo he
either learned it here first-hand or acquired it from someone else who
had learned it here.
"Whatever he's after, his approach certainly varies. He asked you a
lot of questions, Fitz, but, Jim, practically all he did in your house was
tell you your wife was pregnant with quintuplets. And whatever his
approach has been, he never seems to finish whatever he comes to
do. Something about you two—and from what you two have said,
Kozulak and Wohl—seems to have a most peculiar effect on him; you
say he's staggered out of every house he's entered only to recover
again in a matter of seconds.
"Just try to equate that!"
He stopped, pondering, and we didn't interrupt.
"Look," he said, "you two go upstairs. Take opposite sides of the
house and find him. Go slowly so that he won't be alarmed. Try to talk
with him, to persuade him we mean him no harm. If you find you can't
persuade him to come willingly, try to work him back to the passenger
shaft. I'll watch through the console—I've kinescopes in every room—
and I'll lock off one room at a time so that he can't reverse himself. I
won't activate the kinescopes until you're upstairs; he might
deactivate them if he weren't kept busy. Get him back to the
passenger shaft and I'll take over from there."
"But what—" Fitzgerald started.
Browne scowled and we went. Fitzgerald should have known better;
there are no buts when Browne gives orders.
We reached the second floor, floated off the up column into the foyer,
and separated.
Browne's first floor rooms are spacious, but most of those on the
second floor are not. I'd never been on the second floor before; I
found it a honeycomb of interconnected rooms of varying sizes and
shapes. I was apparently in Mrs. Browne's quarters; there were half a
dozen hobby rooms alone: a sewing room, a painting room, a
sculpture room, a writing room, others—And here was her spacious
bedroom and on its far side the alien was vainly trying to force one of
its windows.
He turned as I entered, his curious eyes darting around for an avenue
of escape.
"Now, wait," I said as soothingly as I could. "We don't mean any
harm. I think we're justified in being curious as to why you're here.
Who are you anyway? What are you looking for and why?"
He shook his head as if bewildered and seemed suddenly to become
unsteady.
"One question at a time, please," he said, temporizingly. "Your school
system isn't exacting enough; you all think of too many things at
once. It shocks a mind trained to single subject concentration,
especially when one has been educated in telepathic reception."
He grinned at me as I mentally recalled his staggering moments of
seeming drunkenness.
One question at a time, he'd said. Well, I'd ask him the one that was
burning at the threshold of my mind. I said quickly:
"I realize that you probably read in my mind that my wife and I are
expecting quintuplets, but how did you know the rest—about the
division of sexes—or did you guess?"
"I'll have to explain," he said; then hesitated, seeming to debate
mentally with himself as to whether he should go on. Suddenly he
started to talk so fast that the words nearly blurred into
unrecognizability, like a 45 rpm record at 78.
"I am Hirm Sulay of Alpha Centauri Five," he burst. "My people have
warred with the race of Beta Centauri Three for fifty of your years. We
secretly bring our children here to protect them from sporadic
bombing, insuring their upbringing through placing them in
orphanages or directly into homes."
A horrible suspicion flamed in my mind. I'd tried vainly to account for
the multiple birth we were expecting. I cried at him: "Then my wife—"
and he said,
"She will have twin girls, Doc Gardiner tells me. We had planned to
have three newborn boys ready in the delivery room."
"Then Doc Gardiner—"
"He and his staff are all of my race," Hirm Sulay said. "I see how your
mind leaped when I said 'newborn boys.' Your UFO sightings
frequently describe a 'mother' ship. Considering the gravid women
aboard I'd say the description is quite apt."
For some reason anger flared in me, and I rushed at him. He blurred
and went around me and out the way I'd come. I raced after him and
heard Fitzgerald cry, "Oh, no you don't!" and machine-gun footfalls
were doubling back toward me.
I hurried on and he flashed at and by me, then turned back as he
came to a door Browne had remotely locked. Back at and past me
again. I gave chase.
Fitzgerald yelled, "He's slowing down, Jim. He's tiring!"
And the doors kept closing under Browne's nimble fingering at the
console down below. Suddenly the area was cut down to the
passenger shaft foyer, and the three of us were weaving about, like
two tackles after the fastest fullback of all time. I leaped forward and
actually laid a hand on the alien for a split second, just enough to
topple him off balance so that Fitzgerald, charging in, managed to
bump him successfully into the shaft. A surprised cry came ringing
back up the shaft; Browne had obviously cut the lift's power supply
completely.
Browne's voice came ringing up: "Come on down, fellows; I've got
him!"
The shaft guard light flicked to green. Fitzgerald and I dropped down
to first.
Browne had apparently had his chair directly under the shaft; it was
back from the touchdown pad now and Hirm Sulay was in it, vainly
wriggling, shame-faced.
"Now maybe we'll find out a thing or two—" Browne said
meaningfully, bending toward the alien.
"Wait a minute," I cut in and related what Hirm Sulay had told me
upstairs.
"Is it true?" Browne demanded.
Hirm Sulay nodded.
"But why are you going from door to door? Surely you know where
those children are!"
"Sorry," Hirm Sulay said, "we don't. Some of the older and more
important records were lost. I say more important because the
missing ones I seek are grown. We're fighting a war, as I told you,
Jim. You can't keep fighting a war without young recruits!"
Browne's nearly fantastic dexterity came to my mind then. It
apparently came to his simultaneously; he asked abruptly,
"Could I be one of you?"
"What do you think?" Hirm Sulay countered, his face enigmatic.
"Well, I certainly can't move as fast as you!"
"Have you ever tried? Have you ever gone in for athletics? I'd say no.
Most scientists are essentially inactive—physically, that is."
"Are you saying 'yes'?" Browne cried.
Hirm Sulay looked us over, one by one. "Each of you is of our blood,"
he said. "I knew Jim and Fitz were when Fitz said I was slowing down
upstairs. I wasn't; they were speeding up to normalcy for the first
time."
I was stunned for a moment, only dimly aware that he went on to say,
"Now please turn off this blasted chair and tell me how it works. The
principle applied as a tractor beam could win our war!"
"I haven't the vaguest idea," Browne said. "But I bet you can figure it
out!"
Browne went to the servomech for drinks. He was gone for precisely
three seconds. Of those the servomech took two. Slow machine.
I don't know what to tell Tessie. Maybe she'd feel strange with the
boys if she knew. I'll certainly have to tell her part of the truth, though,
because I just can't let Browne and Fitzgerald go to help win our war
without me.
*** END OF THE PROJECT GUTENBERG EBOOK SECOND
CENSUS ***
Updated editions will replace the previous one—the old editions will
be renamed.
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
ebookmass.com