summaryrefslogtreecommitdiffstats
path: root/courgette/disassembler.cc
blob: 568114c52701816720816b785a74786c66967625 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (c) 2011 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 "courgette/disassembler.h"

#include <stddef.h>
#include <stdint.h>

#include <algorithm>
#include <string>
#include <vector>

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "courgette/assembly_program.h"
#include "courgette/courgette.h"
#include "courgette/disassembler_elf_32_arm.h"
#include "courgette/disassembler_elf_32_x86.h"
#include "courgette/disassembler_win32_x64.h"
#include "courgette/disassembler_win32_x86.h"
#include "courgette/encoded_program.h"

namespace courgette {

////////////////////////////////////////////////////////////////////////////////

Disassembler* DetectDisassembler(const void* buffer, size_t length) {
  Disassembler* disassembler = NULL;

  disassembler = new DisassemblerWin32X86(buffer, length);
  if (disassembler->ParseHeader())
    return disassembler;
  else
    delete disassembler;

  disassembler = new DisassemblerWin32X64(buffer, length);
  if (disassembler->ParseHeader())
    return disassembler;
  else
    delete disassembler;

  disassembler = new DisassemblerElf32X86(buffer, length);
  if (disassembler->ParseHeader())
    return disassembler;
  else
    delete disassembler;

  disassembler = new DisassemblerElf32ARM(buffer, length);
  if (disassembler->ParseHeader())
    return disassembler;
  else
    delete disassembler;

  return NULL;
}

Status DetectExecutableType(const void* buffer, size_t length,
                            ExecutableType* type,
                            size_t* detected_length) {

  Disassembler* disassembler = DetectDisassembler(buffer, length);

  if (disassembler) {
    *type = disassembler->kind();
    *detected_length = disassembler->length();
    delete disassembler;
    return C_OK;
  }

  // We failed to detect anything
  *type = EXE_UNKNOWN;
  *detected_length = 0;
  return C_INPUT_NOT_RECOGNIZED;
}

Status ParseDetectedExecutable(const void* buffer, size_t length,
                               AssemblyProgram** output) {
  *output = nullptr;

  scoped_ptr<Disassembler> disassembler(DetectDisassembler(buffer, length));
  if (!disassembler)
    return C_INPUT_NOT_RECOGNIZED;

  scoped_ptr<AssemblyProgram> program(
      new AssemblyProgram(disassembler->kind()));

  if (!disassembler->Disassemble(program.get()))
    return C_DISASSEMBLY_FAILED;

  if (!program->TrimLabels())
    return C_TRIM_FAILED;

  *output = program.release();
  return C_OK;
}

void DeleteAssemblyProgram(AssemblyProgram* program) {
  delete program;
}

Disassembler::Disassembler(const void* start, size_t length)
  : failure_reason_("uninitialized") {
  start_ = reinterpret_cast<const uint8_t*>(start);
  length_ = length;
  end_ = start_ + length_;
};

Disassembler::~Disassembler() {};

const uint8_t* Disassembler::OffsetToPointer(size_t offset) const {
  assert(start_ + offset <= end_);
  return start_ + offset;
}

bool Disassembler::Good() {
  failure_reason_ = NULL;
  return true;
}

bool Disassembler::Bad(const char* reason) {
  failure_reason_ = reason;
  return false;
}

void Disassembler::ReduceLength(size_t reduced_length) {
  CHECK_LE(reduced_length, length_);
  length_ = reduced_length;
  end_ = start_ + length_;
}

}  // namespace courgette