Skip to content

Commit

Permalink
Add full source based on private commit f3d50bd
Browse files Browse the repository at this point in the history
  • Loading branch information
jonpalmisc committed Nov 24, 2023
1 parent e523067 commit b5153b9
Show file tree
Hide file tree
Showing 39 changed files with 2,145 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
BasedOnStyle: LLVM

AlignConsecutiveMacros: true
...
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src/payload/*.h
*.bin
18 changes: 18 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[submodule "external/jsx"]
path = external/jsx
url = [email protected]:jonpalmisc/jsx.git
[submodule "external/sioku"]
path = external/sioku
url = [email protected]:jonpalmisc/sioku.git
[submodule "external/argh"]
path = external/argh
url = [email protected]:adishavit/argh.git
[submodule "external/linenoise"]
path = external/linenoise
url = [email protected]:jonpalmisc/linenoise.git
[submodule "external/lua"]
path = external/lua
url = [email protected]:jonpalmisc/cmake_lua.git
[submodule "external/sol2"]
path = external/sol2
url = [email protected]:ThePhD/sol2.git
45 changes: 45 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(respawn VERSION 0.1.0)

add_subdirectory(external/argh EXCLUDE_FROM_ALL)
add_subdirectory(external/sioku EXCLUDE_FROM_ALL)
add_subdirectory(external/jsx EXCLUDE_FROM_ALL)
add_subdirectory(external/linenoise EXCLUDE_FROM_ALL)

set(LUA_BUILD_COMPILER OFF)
set(LUA_BUILD_INTERPRETER OFF)
add_subdirectory(external/lua EXCLUDE_FROM_ALL)
add_subdirectory(external/sol2 EXCLUDE_FROM_ALL)

add_executable(respawn
src/exploit/driver.cpp
src/implant/client.cpp
src/implant/message.c
src/main.cpp
src/payload/builder.cpp
src/repl.cpp
src/usb/client.cpp)
target_compile_features(respawn PRIVATE cxx_std_17)
target_include_directories(respawn PRIVATE include)
target_link_libraries(respawn PRIVATE
argh
sioku
jsx::log
jsx::hex
linenoise
lua::lang
sol2::sol2)

include(cmake/Payload.cmake)
add_payload(respawn src/payload/bootstrap.s)
add_payload(respawn src/payload/implant.s)

install(TARGETS respawn DESTINATION .)
install(DIRECTORY lua DESTINATION .)

set(CPACK_GENERATOR TXZ)
set(CPACK_STRIP_FILES ON)
set(CPACK_PACKAGE_NAME Respawn)
set(CPACK_PACKAGE_CHECKSUM SHA256)
include(CPack)
26 changes: 26 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Copyright (c) 2022-2023 Jon Palmisciano. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 changes: 29 additions & 0 deletions cmake/Payload.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
set(PAYLOAD_ASSEMBLER ${CMAKE_C_COMPILER})
set(PAYLOAD_ASSEMBLER_FLAGS
-target arm64-apple-darwin
-Oz
-I${CMAKE_SOURCE_DIR}/include
-DPAYLOAD_SOURCE)

function(add_payload PARENT SOURCE)
get_filename_component(NAME ${SOURCE} NAME_WE)
set(HEADER src/payload/${NAME}.h)
set(OBJECT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.o)
set(BINARY ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.bin)

# The generated header needs to be made a dependency of some other (normal)
# target so that it is actually generated.
target_sources(${PARENT} PRIVATE ${HEADER})

add_custom_command(
COMMENT "Generating payload header ${HEADER}"
OUTPUT ${CMAKE_SOURCE_DIR}/${HEADER} DEPENDS ${SOURCE}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${PAYLOAD_ASSEMBLER} ${PAYLOAD_ASSEMBLER_FLAGS} -o ${OBJECT} -c ${SOURCE}
COMMAND segedit ${OBJECT} -extract __TEXT __text ${BINARY}
COMMAND printf "%s\\n\\n" "// This file is auto-generated. Do not edit!" > ${HEADER}
COMMAND printf "%s\\n\\n" "#pragma once" >> ${HEADER}
COMMAND xxd -n ${NAME} -i ${BINARY} >> ${HEADER}
COMMAND rm ${OBJECT}
VERBATIM)
endfunction()
1 change: 1 addition & 0 deletions external/argh
Submodule argh added at c429ee
1 change: 1 addition & 0 deletions external/jsx
Submodule jsx added at e3fa52
1 change: 1 addition & 0 deletions external/linenoise
Submodule linenoise added at d99a6d
1 change: 1 addition & 0 deletions external/lua
Submodule lua added at fb8ca8
1 change: 1 addition & 0 deletions external/sioku
Submodule sioku added at c50111
1 change: 1 addition & 0 deletions external/sol2
Submodule sol2 added at 9c882a
17 changes: 17 additions & 0 deletions include/respawn/chip.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// Copyright (c) 2022-2023 Jon Palmisciano. All rights reserved.
//
// Use of this source code is governed by the BSD 3-Clause license; a full
// copy of the license can be found in the LICENSE.txt file.
//

#pragma once

/// Known SoC chip IDs.
enum class Chip {
Invalid = 0,

T7000 = 0x7000, // A8
S8000 = 0x8000, // A9, Samsung
S8003 = 0x8003, // A9, TSMC
};
52 changes: 52 additions & 0 deletions include/respawn/dfu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// Copyright (c) 2022-2023 Jon Palmisciano. All rights reserved.
//
// Use of this source code is governed by the BSD 3-Clause license; a full
// copy of the license can be found in the LICENSE.txt file.
//

#pragma once

#include <cstdint>

constexpr auto DFU_FILE_SUFFIX_SIZE = 0x10;
constexpr auto DFU_MAX_TRANSFER_SIZE = 0x800;

// Like the USB request type flags, the enums below need to be used as integers
// since they are actually being sent and received over the wire. Once again,
// template hacks could be used to enable implicit conversions, etc. but
// begrudgingly using a C-style enum is more straightforward. See the comment
// on the `UsbRequestTypeFlags` enum for more context.

/// DFU request types.
enum DfuRequest {
DFU_REQUEST_DOWNLOAD = 1,
DFU_REQUEST_UPLOAD = 2,
DFU_REQUEST_GET_STATUS = 3,
DFU_REQUEST_CLEAR_STATUS = 4,
};

/// DFU status.
enum DfuStatus : uint8_t {
DFU_STATUS_OK = 0,
};

/// DFU state.
enum DfuState : uint8_t {
DFU_STATE_MANIFEST_SYNC = 6,
DFU_STATE_MANIFEST = 7,
DFU_STATE_MANIFEST_WAIT_RESET = 8,
};

/// Reply structure returned by `DFU_GETSTATUS` requests.
struct DfuStatusReply {
DfuStatus status;
uint8_t timeout[3];
DfuState state;
uint8_t index;

/// Check if the reply has the expected status and state.
[[nodiscard]] bool has_state(DfuStatus status, DfuState state) const {
return this->status == status && this->state == state;
}
};
41 changes: 41 additions & 0 deletions include/respawn/exploit/driver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Copyright (c) 2022-2023 Jon Palmisciano. All rights reserved.
//
// Use of this source code is governed by the BSD 3-Clause license; a full
// copy of the license can be found in the LICENSE.txt file.
//

#pragma once

#include "respawn/chip.h"
#include "respawn/usb/client.h"

/// USB client responsible for "driving" the exploit process.
///
/// This is a superset of the standard USB client class, but with additional
/// primitives used in the exploit process and a full exploit implementation.
class ExploitDriver : public UsbClient {
Chip m_chip;
bool m_dump_payloads;

/// Save a payload to the disk.
static void dump_payload(std::vector<uint8_t> const &payload,
const std::string &name);

bool do_no_leak();
bool do_request_stall();
bool do_request_leak();

bool run_reset_step();
bool run_setup_step();
bool run_patch_step();

public:
ExploitDriver(UsbClient const &client, Chip chip, bool dump_payloads = false);

/// Run the entire exploit.
///
/// It is assumed that the device is in a "clean DFU" state at this point in
/// time, which is the responsibility of the caller to check.
bool run();
};
65 changes: 65 additions & 0 deletions include/respawn/implant/client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// Copyright (c) 2022-2023 Jon Palmisciano. All rights reserved.
//
// Use of this source code is governed by the BSD 3-Clause license; a full
// copy of the license can be found in the LICENSE.txt file.
//

#pragma once

#include "respawn/implant/message.h"
#include "respawn/usb/client.h"

/// Register state shorthand type.
///
/// Despite being a vector, functions returning this type will always provide
/// exactly eight elements, and only the first eight elements will ever be used
/// when this type is recieved as an argument.
///
/// TODO: Make this a `std::array`.
using RegisterState = std::vector<uint64_t>;

/// Implant communication client.
///
/// Supports reading and writing device memory, as well as branching to
/// arbitrary addresses with user-controlled register states.
class ImplantClient : public UsbClient {

/// Send arbitrary data to the device.
///
/// The implant (as well as the hook installed by the initial exploit) both
/// communicate by sending data over DFU; under the hood, this is really
/// performing a DFU "download" of the given data, which will then be
/// interpreted by the initial hook or implant.
UsbTransferResult send_data(void *data, size_t size);

/// Send an implant message to the device.
UsbTransferResult send_message(RspnMessage &message);

/// Perform a single-packet memory read, obeying the maximum packet size.
std::vector<uint8_t> read_memory_single(uint64_t address, uint32_t length);

/// Perform a single-packet memory write, obeying the maximum packet size.
bool write_memory_single(uint64_t address, uint8_t const *data,
uint32_t length);

public:
explicit ImplantClient(UsbClient const &);

/// Install the implant; must be called first.
bool install();

/// Send test message to check if the implant is installed and functional.
bool test();

/// Read data from the device's memory.
std::vector<uint8_t> read_memory(uint64_t address, uint32_t length);

/// Write data to the device's memory.
bool write_memory(uint64_t address, std::vector<uint8_t> const &data);
bool write_memory(uint64_t address, uint8_t const *data, uint32_t length);

/// Make the device branch and link to the destination address, using
/// the supplied registers as arguments.
RegisterState execute(uint64_t destination, RegisterState const &args);
};
45 changes: 45 additions & 0 deletions include/respawn/implant/message.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// Copyright (c) 2022-2023 Jon Palmisciano. All rights reserved.
//
// Use of this source code is governed by the BSD 3-Clause license; a full
// copy of the license can be found in the LICENSE.txt file.
//

#pragma once

#include "respawn/implant/protocol.h"

// The message infrastructure was originally intended to be portable between
// the host and payloads written in C; as such, it is written in pure C rather
// than C++, like the rest of the project.
#ifdef __cplusplus
extern "C" {
#endif

#include "stdint.h"

/// Custom "packet" structure used to communicate with the implant via USB.
typedef struct __attribute__((packed)) {
uint64_t magic;

uint32_t type;
uint32_t reserved;
uint64_t arg;

uint64_t length;
uint8_t body[RSPN_MESSAGE_BODY_SIZE];
} RspnMessage;

/// Initialize a message.
void rspn_message_init(RspnMessage *message, uint32_t type, uint64_t arg);

/// Clear a message's body.
void rspn_message_clear_body(RspnMessage *message);

/// Set a message's body.
void rspn_message_set_body(RspnMessage *message, uint8_t const *data,
uint16_t length);

#ifdef __cplusplus
}
#endif
21 changes: 21 additions & 0 deletions include/respawn/implant/protocol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Copyright (c) 2022-2023 Jon Palmisciano. All rights reserved.
//
// Use of this source code is governed by the BSD 3-Clause license; a full
// copy of the license can be found in the LICENSE.txt file.
//

#pragma once

// WARNING: This file is included from both C/C++ code as well as assembly and
// must remain compatible with both!

#define RSPN_MESSAGE_MAGIC 0x2d2a4e5053522a2d

#define RSPN_MESSAGE_BODY_SIZE 0x100

#define RSPN_MESSAGE_TYPE_INVALID 0
#define RSPN_MESSAGE_TYPE_EXECUTE 0x45 /* E */
#define RSPN_MESSAGE_TYPE_READ 0x52 /* R */
#define RSPN_MESSAGE_TYPE_WRITE 0x57 /* W */
#define RSPN_MESSAGE_TYPE_TEST 0x54 /* T */
Loading

0 comments on commit b5153b9

Please sign in to comment.