-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 387a4f3
Showing
15 changed files
with
1,840 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
*~ | ||
\#*\# | ||
.\#* | ||
result | ||
build |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
CC ?= arm-remarkable-linux-gnueabi-gcc | ||
LD ?= arm-remarkable-linux-gnueabi-ld | ||
AR ?= arm-remarkable-linux-gnueabi-ar | ||
OBJCOPY ?= arm-remarkable-linux-gnueabi-objcopy | ||
|
||
.PHONY: all clean | ||
|
||
all: build/libqsgepaper_extract_info | ||
all: build/payload.bin | ||
all: build/libqsgepaper-snoop.so build/libqsgepaper-snoop-standalone.a | ||
clean: | ||
rm -rf build | ||
|
||
build: | ||
mkdir -p build | ||
build/%.o: %.c | build | ||
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS) | ||
build/%.o: %.s | build | ||
$(CC) $(ASFLAGS) -c $< -o $@ $(LDFLAGS) | ||
build/%.a: | build | ||
$(AR) cr $@ $^ | ||
build/%.so: | build | ||
$(CC) -shared -z defs -o $@ $^ $(LDFLAGS) | ||
build/%.xz: build/% | build | ||
xz -f -k $< | ||
|
||
build/extract_info.o: cached_info.h | ||
build/libqsgepaper_extract_info: build/extract_info.o | build | ||
$(CC) $< -o $@ -Wl,--start-group -lunicorn -larm-softmmu -Wl,--end-group -lpthread | ||
build/libqsgepaper_extract_info.bin: build/libqsgepaper_extract_info.xz | ||
$(OBJCOPY) -I binary -O elf32-littlearm -B arm $< $@ | ||
|
||
build/payload-a.o: private ASFLAGS=-ffreestanding | ||
build/payload-c.o: private CFLAGS=-ffreestanding -fno-stack-protector -fPIE -fno-plt -mpic-data-is-text-relative | ||
build/payload.o: build/payload-a.o build/payload-c.o payload.ld | build | ||
$(LD) -Tpayload.ld -s build/payload-c.o build/payload-a.o -o $@ | ||
build/payload.bin: build/payload.o | ||
$(OBJCOPY) -O binary -j .binary $< $@ | ||
|
||
build/inject.o: cached_info.h | ||
build/inject-standalone.o: build/inject.o inject-standalone.ld build/libqsgepaper_extract_info.bin build/payload.o | build | ||
$(LD) -Tinject-standalone.ld -i -o $@ build/inject.o | ||
|
||
build/libqsgepaper-snoop-standalone.a: build/inject-standalone.o | ||
|
||
build/libqsgepaper-snoop.so: build/inject.o | ||
build/libqsgepaper-snoop.so: private override LDFLAGS += -lcrypto -llzma |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# Introduction | ||
|
||
This library provides damage tracking information version 2 of the | ||
[reMarkable tablet](https://remarkable.com). Unlike the reMarkable 1, | ||
the reMarkable 2 does not use the integrated e-paper display | ||
controller on the SoC used for the system, but instead drives the | ||
display directly from software. This makes it impossible to extract | ||
damage information from the (nonexistent) hardware driver, which was | ||
the approach taken on the rM1. | ||
|
||
It is therefore necessary to inject code into the process that _is_ | ||
controlling the framebuffer in order to provide notification of damage | ||
update. In all known production software, the display is controlled by | ||
executables using the proprietary static library `libqsgepaper.a`. The | ||
purpose of this project, therefore, is to inject code into a | ||
`libqsgepaper.a`-based binary that exports the software framebuffer to | ||
which content is drawn, as well as damage notifications whenever an | ||
update is sent to the display. | ||
|
||
In order to work on as wide a range of driving binaries as possible, | ||
this library avoids using hardcoded addresses or similar techniques. | ||
Instead, it uses data taken from Qt metaobjects that are part of the | ||
interface of `libqsgepaper.a` in order to locate relevant functions | ||
and data. | ||
|
||
It is relatively easy to find the Qt metaobject in the data section of | ||
the binary@riving the display. Unfortunately, this does not give | ||
direct access to the virtual framebuffer, or to the function used to | ||
notify the display that an update is present. In order to find these | ||
things, the [Unicorn Engine](https://www.unicorn-engine.org/) emulator | ||
is used to emulate the Qt static meta-call function (when given | ||
appropriate parameters). This uses the fact that `libqsgepaper.a` | ||
passes the framebuffer address to `QImage::fill` in the (inlined) | ||
`clearScreen` function, the fact that `sendUpdate` is not inlined into | ||
`QObject::metacall`, and little else. | ||
|
||
Once the appropriate addresses have been found, a writable and | ||
executable page is `mmap`d via ptrace()ing the target process, and a | ||
payload built from [payload-c.c](./payload-c.c) and | ||
[payload-a.s](./payload-a.s) is injected. The preamble of the | ||
`sendUpdate` function in the original process is overwritten to | ||
redirect to a portion of the payload which saves the information | ||
damaged, runs the original `sendUpdate`,and then exports the damage | ||
information over a Unix domain socket. The payload also includes | ||
initialization code that replaces the private anonymous mapping of the | ||
framebuffer with a shared mapping backed by an in-memory file from | ||
`memfd_create` and connects to a Unix domain socket opened by the | ||
process requesting the information. | ||
|
||
The necessary addresses appear to in practice remain stable over | ||
multiple executions of the same binary, as the `EPFramebuffer` class | ||
which is being hooked into is a singleton and address-space layout | ||
randomization is not used on the reMarkable. Therefore, in order to | ||
improve startup time and minimize resource usage, the Unicorn-based | ||
emulation analysis is not run every time, but rather stored in a | ||
cache. | ||
|
||
# Building | ||
|
||
The supported way to build this is via the | ||
[Nix](https://nixos.org/nix) package manager, through the | ||
[nix-remarkable](https://github.com/peter-sa/nix-remarkable) | ||
expressions. To build just this project via `nix build` from this | ||
repo, download it into the `pkgs/` directory of `nix-remarkable`. | ||
|
||
For other systems, the [Makefile](./Makefile) provides the necessary | ||
commands. A suitable build of the Unicorn engine (static for the | ||
standalone static library) is required. | ||
|
||
Prebuilt binaries are available in the [Releases | ||
tab](https://github.com/pl-semiotics/libqsgepaper-snoop/releases). | ||
|
||
# Usage | ||
|
||
See [libqsgepaper-snoop.h](./libqsgepaper-snoop.h). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#ifndef CACHED_INFO_H_ | ||
#define CACHED_INFO_H_ | ||
|
||
#include <sys/types.h> | ||
|
||
#include "private.h" | ||
|
||
#define HEADER_MAGIC "libqsgepaper-snoop cached info v1\n" | ||
#define SIZE_BYTE sizeof(HEADER_MAGIC) | ||
#define STATE_BEGIN sizeof(HEADER_MAGIC) + sizeof(uint); | ||
|
||
struct check_bit { | ||
uint addr; | ||
uint eval; | ||
}; | ||
struct cached_state { | ||
uint qimage_bits_addr_addr; | ||
uint mmap_addr_addr; | ||
uint fb_addr; | ||
uint sendUpdate_addr; | ||
/* the user code could use this directly, but really it's used for | ||
* checking that nothing's changed. however, since we might have | ||
* injected already, it doesn't go in cbits below. | ||
*/ | ||
uint su_preamble[N_PREAMBLE_INSTRS]; | ||
/* for verification that this is the correct executable only */ | ||
uint ncbits; | ||
struct check_bit cbits[]; | ||
}; | ||
|
||
#endif /* CACHED_INFO_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
(import ../.. {}).rmPkgs.libqsgepaper-snoop |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ stdenv, lib, unicorn }: | ||
|
||
stdenv.mkDerivation { | ||
pname = "libqsgepaper-snoop"; | ||
version = "0.0.1"; | ||
src = lib.cleanSource ./.; | ||
buildInputs = [ unicorn ]; | ||
installPhase = '' | ||
mkdir -p $out/lib | ||
cp build/libqsgepaper-snoop.so $out/lib | ||
cp build/libqsgepaper-snoop-standalone.a $out/lib | ||
mkdir -p $out/share/libqsgepaper-snoop | ||
cp build/payload.bin $out/share/libqsgepaper-snoop | ||
mkdir -p $out/libexec/libqsgepaper-snoop | ||
cp build/libqsgepaper_extract_info $out/libexec/libqsgepaper-snoop | ||
mkdir -p $out/include | ||
cp libqsgepaper-snoop.h $out/include | ||
''; | ||
} |
Oops, something went wrong.