aboutsummaryrefslogtreecommitdiff
path: root/rel32_finder.cc
diff options
context:
space:
mode:
authorSamuel Huang <huangs@chromium.org>2018-03-13 18:19:34 +0000
committerEdward Lesmes <ehmaldonado@google.com>2021-07-23 21:50:59 +0000
commit06f1ae9aaca969ee95ef840f22b6b461c304542d (patch)
treef1e5c6624e70628e81fbf38d6cd14b974abe5d93 /rel32_finder.cc
downloadzucchini-06f1ae9aaca969ee95ef840f22b6b461c304542d.tar.gz
[Zucchini] Move Zucchini from /chrome/installer/ to /components/.
(Use "git log --follow" to see older revisions of files). /components/ is the most logical place to put Zucchini, which only depends on /base and /testing/gtest. This move also enables Zucchini to be used by the Component Updater. Details: - Move all files; run the following to change deps and guards: sed 's/chrome\/installer/components/' *.cc *.h -i sed 's/CHROME_INSTALLER/COMPONENTS/' *.cc *.h -i - Sorting works out pretty well! - Change all 'chrome/installer/zucchini' to 'components/zucchini' throughout other parts of the repo; sort if necessary. - Fix 6 'git cl lint' errors. - Change 1 Bind() usage to BindRepeated(). - Update OWNER. Bug: 729154 Change-Id: I50c5a7d411ea85f707b5994ab319dfb2a1acccf7 Reviewed-on: https://chromium-review.googlesource.com/954923 Reviewed-by: Greg Thompson <grt@chromium.org> Reviewed-by: Jochen Eisinger <jochen@chromium.org> Reviewed-by: Samuel Huang <huangs@chromium.org> Commit-Queue: Samuel Huang <huangs@chromium.org> Cr-Commit-Position: refs/heads/master@{#542857} NOKEYCHECK=True GitOrigin-RevId: 577ef6c435e8d43be6e3e60ccbcbd1881780f4ec
Diffstat (limited to 'rel32_finder.cc')
-rw-r--r--rel32_finder.cc137
1 files changed, 137 insertions, 0 deletions
diff --git a/rel32_finder.cc b/rel32_finder.cc
new file mode 100644
index 0000000..9a07ade
--- /dev/null
+++ b/rel32_finder.cc
@@ -0,0 +1,137 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/zucchini/rel32_finder.h"
+
+#include <algorithm>
+
+namespace zucchini {
+
+/******** Abs32GapFinder ********/
+
+Abs32GapFinder::Abs32GapFinder(ConstBufferView image,
+ ConstBufferView region,
+ const std::vector<offset_t>& abs32_locations,
+ size_t abs32_width)
+ : base_(image.begin()),
+ region_end_(region.end()),
+ abs32_end_(abs32_locations.end()),
+ abs32_width_(abs32_width) {
+ DCHECK_GT(abs32_width, size_t(0));
+ DCHECK_GE(region.begin(), image.begin());
+ DCHECK_LE(region.end(), image.end());
+
+ const offset_t begin_offset = region.begin() - image.begin();
+ // Find the first |abs32_current_| with |*abs32_current_ >= begin_offset|.
+ abs32_current_ = std::lower_bound(abs32_locations.begin(),
+ abs32_locations.end(), begin_offset);
+
+ // Find lower boundary, accounting for possibility that |abs32_current_[-1]|
+ // may straddle across |region.begin()|.
+ current_lo_ = region.begin();
+ if (abs32_current_ > abs32_locations.begin()) {
+ current_lo_ = std::max(current_lo_,
+ image.begin() + abs32_current_[-1] + abs32_width_);
+ }
+}
+
+Abs32GapFinder::~Abs32GapFinder() = default;
+
+base::Optional<ConstBufferView> Abs32GapFinder::GetNext() {
+ // Iterate over |[abs32_current_, abs32_end_)| and emit segments.
+ while (abs32_current_ != abs32_end_ &&
+ base_ + *abs32_current_ < region_end_) {
+ ConstBufferView::const_iterator hi = base_ + *abs32_current_;
+ ConstBufferView gap = ConstBufferView::FromRange(current_lo_, hi);
+ current_lo_ = hi + abs32_width_;
+ ++abs32_current_;
+ if (!gap.empty())
+ return gap;
+ }
+ // Emit final segment.
+ if (current_lo_ < region_end_) {
+ ConstBufferView gap = ConstBufferView::FromRange(current_lo_, region_end_);
+ current_lo_ = region_end_;
+ return gap;
+ }
+ return base::nullopt;
+}
+
+/******** Rel32Finder ********/
+
+Rel32Finder::Rel32Finder() = default;
+
+Rel32Finder::Rel32Finder(ConstBufferView region)
+ : region_(region), next_cursor_(region_.begin()) {}
+
+Rel32Finder::~Rel32Finder() = default;
+
+/******** Rel32FinderX86 ********/
+
+ConstBufferView Rel32FinderX86::Scan(ConstBufferView region) {
+ ConstBufferView::const_iterator cursor = region.begin();
+ while (cursor < region.end()) {
+ // Heuristic rel32 detection by looking for opcodes that use them.
+ if (cursor + 5 <= region.end()) {
+ if (cursor[0] == 0xE8 || cursor[0] == 0xE9) { // JMP rel32; CALL rel32
+ rel32_ = {cursor + 1, false};
+ return ConstBufferView::FromRange(cursor, rel32_.location + 4);
+ }
+ }
+ if (cursor + 6 <= region.end()) {
+ if (cursor[0] == 0x0F && (cursor[1] & 0xF0) == 0x80) { // Jcc long form
+ rel32_ = {cursor + 2, false};
+ return ConstBufferView::FromRange(cursor, rel32_.location + 4);
+ }
+ }
+ ++cursor;
+ }
+ return {region.end(), 0};
+}
+
+/******** Rel32FinderX64 ********/
+
+ConstBufferView Rel32FinderX64::Scan(ConstBufferView region) {
+ ConstBufferView::const_iterator cursor = region.begin();
+ while (cursor < region.end()) {
+ // Heuristic rel32 detection by looking for opcodes that use them.
+ if (cursor + 5 <= region.end()) {
+ if (cursor[0] == 0xE8 || cursor[0] == 0xE9) { // JMP rel32; CALL rel32
+ rel32_ = {cursor + 1, false};
+ return ConstBufferView::FromRange(cursor, rel32_.location + 4);
+ }
+ }
+ if (cursor + 6 <= region.end()) {
+ if (cursor[0] == 0x0F && (cursor[1] & 0xF0) == 0x80) { // Jcc long form
+ rel32_ = {cursor + 2, false};
+ return ConstBufferView::FromRange(cursor, rel32_.location + 4);
+ } else if ((cursor[0] == 0xFF &&
+ (cursor[1] == 0x15 || cursor[1] == 0x25)) ||
+ ((cursor[0] == 0x89 || cursor[0] == 0x8B ||
+ cursor[0] == 0x8D) &&
+ (cursor[1] & 0xC7) == 0x05)) {
+ // 6-byte instructions:
+ // [2-byte opcode] [disp32]:
+ // Opcode
+ // FF 15: CALL QWORD PTR [rip+disp32]
+ // FF 25: JMP QWORD PTR [rip+disp32]
+ //
+ // [1-byte opcode] [ModR/M] [disp32]:
+ // Opcode
+ // 89: MOV DWORD PTR [rip+disp32],reg
+ // 8B: MOV reg,DWORD PTR [rip+disp32]
+ // 8D: LEA reg,[rip+disp32]
+ // ModR/M : MMRRRMMM
+ // MM = 00 & MMM = 101 => rip+disp32
+ // RRR: selects reg operand from [eax|ecx|...|edi]
+ rel32_ = {cursor + 2, true};
+ return ConstBufferView::FromRange(cursor, rel32_.location + 4);
+ }
+ }
+ ++cursor;
+ }
+ return {region.end(), 0};
+}
+
+} // namespace zucchini