diff --git a/README.md b/README.md
index a4db042eadd222cb25390e56792427a5b2c51010..b3482af4d4afc2227c143ebb3b9aada5e5ae95e9 100644
--- a/README.md
+++ b/README.md
@@ -20,4 +20,4 @@ On Android versions earlier than 7.1 (API 25), you may need to use [Conscrypt](h
 
     implementation 'org.conscrypt:conscrypt-android:2.5.2'
 
-Finally, you must also provide a suitable [obfs4proxy](https://gitweb.torproject.org/pluggable-transports/obfs4.git/tree/README.md) binary for your platform.
+Finally, you must also provide a suitable meek implementation, such as [lyrebird](https://gitweb.torproject.org/pluggable-transports/lyrebird.git/tree/README.md), for your platform.
diff --git a/app/build.gradle b/app/build.gradle
index 090845c62f9eface7e6e4416b95b00afc6a73160..573937447879f7988ef6895298043599998e9997 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -62,7 +62,7 @@ dependencies {
     implementation 'com.google.dagger:hilt-android:2.44'
     implementation 'org.conscrypt:conscrypt-android:2.5.2'
 
-    tor 'org.briarproject:obfs4proxy-android:0.0.14'
+    tor 'org.briarproject:lyrebird-android:0.5.0-2'
 
     annotationProcessor 'com.google.dagger:hilt-compiler:2.44'
 }
diff --git a/app/src/main/java/org/briarproject/moattest/MainViewModel.java b/app/src/main/java/org/briarproject/moattest/MainViewModel.java
index 510e042c4e4f6c463a5123e1b2661e439bbceafd..34459a942ebbce19cb7d061746f10a6f61cd0b3d 100644
--- a/app/src/main/java/org/briarproject/moattest/MainViewModel.java
+++ b/app/src/main/java/org/briarproject/moattest/MainViewModel.java
@@ -26,7 +26,7 @@ import static java.util.Locale.ROOT;
 @HiltViewModel
 class MainViewModel extends AndroidViewModel {
 
-	private static final String OBFS4_LIB_NAME = "libobfs4proxy.so";
+	private static final String LYREBIRD_LIB_NAME = "liblyrebird.so";
 	private static final String STATE_DIR_NAME = "state";
 
 	private static final String FASTLY_URL = "https://moat.torproject.org.global.prod.fastly.net/";
@@ -58,11 +58,11 @@ class MainViewModel extends AndroidViewModel {
 		countryCode = countryCode.toLowerCase(ROOT);
 		Application app = getApplication();
 		String nativeLibDir = app.getApplicationInfo().nativeLibraryDir;
-		File obfs4Lib = new File(nativeLibDir, OBFS4_LIB_NAME);
+		File lyrebirdLib = new File(nativeLibDir, LYREBIRD_LIB_NAME);
 		File stateDir = app.getDir(STATE_DIR_NAME, MODE_PRIVATE);
 		String url = azure ? AZURE_URL : FASTLY_URL;
 		String front = azure ? AZURE_FRONT : FASTLY_FRONT;
-		MoatApi moat = new MoatApi(obfs4Lib, stateDir, url, front);
+		MoatApi moat = new MoatApi(lyrebirdLib, stateDir, url, front);
 		try {
 			List<Bridges> bridges = moat.getWithCountry(countryCode);
 			StringBuilder sb = new StringBuilder();
diff --git a/lib/build.gradle b/lib/build.gradle
index 8cdc23d0ad662ef21cfdb328bc9ba6d959078833..a4bfb83eb647e503924a5e2935aeb81a56ff8343 100644
--- a/lib/build.gradle
+++ b/lib/build.gradle
@@ -25,8 +25,8 @@ dependencies {
     implementation 'org.briarproject:null-safety:0.1'
     implementation 'org.briarproject:socks-socket:0.1'
 
-    // Linux obfs4proxy binary is only used for testing
-    tor 'org.briarproject:obfs4proxy-linux:0.0.14'
+    // Linux lyrebird binary is only used for testing
+    tor 'org.briarproject:lyrebird-linux:0.5.0-2'
 
     // Test with obsolete version 3.12.x to ensure library users can use it
     // if they need Android 4 compatibility
diff --git a/lib/src/main/java/org/briarproject/moat/MoatApi.java b/lib/src/main/java/org/briarproject/moat/MoatApi.java
index 9ea4ef91438812409714023bd4f38d23e255a7f0..522d157d375b6b3d1a92a78d0903e7dde4f6fc09 100644
--- a/lib/src/main/java/org/briarproject/moat/MoatApi.java
+++ b/lib/src/main/java/org/briarproject/moat/MoatApi.java
@@ -44,16 +44,16 @@ public class MoatApi {
 	private static final int EXTRA_SOCKET_TIMEOUT = (int) SECONDS.toMillis(30);
 	private static final String SOCKS_PASSWORD = "\u0000";
 
-	private final File obfs4Executable, obfs4Dir;
+	private final File lyrebirdExecutable, lyrebirdDir;
 	private final String url, front;
 	private final JsonMapper mapper = JsonMapper.builder()
 			.enable(BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES)
 			.build();
 
-	public MoatApi(File obfs4Executable, File obfs4Dir, String url, String front) {
-		if (!obfs4Dir.isDirectory()) throw new IllegalArgumentException();
-		this.obfs4Executable = obfs4Executable;
-		this.obfs4Dir = obfs4Dir;
+	public MoatApi(File lyrebirdExecutable, File lyrebirdDir, String url, String front) {
+		if (!lyrebirdDir.isDirectory()) throw new IllegalArgumentException();
+		this.lyrebirdExecutable = lyrebirdExecutable;
+		this.lyrebirdDir = lyrebirdDir;
 		this.url = url;
 		this.front = front;
 	}
@@ -63,9 +63,9 @@ public class MoatApi {
 	}
 
 	public List<Bridges> getWithCountry(String country) throws IOException {
-		Process obfs4Process = startObfs4();
+		Process lyrebirdProcess = startLyrebird();
 		try {
-			int port = getPort(obfs4Process);
+			int port = getPort(lyrebirdProcess);
 			String socksUsername = "url=" + url + ";front=" + front;
 			SocketFactory socketFactory = new SocksSocketFactory(
 					new InetSocketAddress("localhost", port),
@@ -93,7 +93,7 @@ public class MoatApi {
 			String responseJson = responseBody.string();
 			return parseResponse(responseJson);
 		} finally {
-			obfs4Process.destroy();
+			lyrebirdProcess.destroy();
 		}
 	}
 
@@ -127,11 +127,11 @@ public class MoatApi {
 		return new Bridges(type, source, bridges);
 	}
 
-	private Process startObfs4() throws IOException {
-		ProcessBuilder pb = new ProcessBuilder(obfs4Executable.getAbsolutePath());
+	private Process startLyrebird() throws IOException {
+		ProcessBuilder pb = new ProcessBuilder(lyrebirdExecutable.getAbsolutePath());
 		Map<String, String> env = pb.environment();
 		env.put("TOR_PT_MANAGED_TRANSPORT_VER", "1");
-		env.put("TOR_PT_STATE_LOCATION", obfs4Dir.getAbsolutePath());
+		env.put("TOR_PT_STATE_LOCATION", lyrebirdDir.getAbsolutePath());
 		env.put("TOR_PT_EXIT_ON_STDIN_CLOSE", "1");
 		env.put("TOR_PT_CLIENT_TRANSPORTS", "meek_lite");
 		pb.redirectErrorStream(true);
diff --git a/lib/src/test/java/org/briarproject/moat/MoatApiTest.java b/lib/src/test/java/org/briarproject/moat/MoatApiTest.java
index 910ffbada5a16420d22bd4bb71e3fd582011423a..642a1446e59581cc17bfc3a0dbd20e10e106100f 100644
--- a/lib/src/test/java/org/briarproject/moat/MoatApiTest.java
+++ b/lib/src/test/java/org/briarproject/moat/MoatApiTest.java
@@ -10,7 +10,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.List;
-import java.util.zip.ZipInputStream;
 
 import static java.util.Collections.emptyList;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -24,15 +23,17 @@ public class MoatApiTest {
 			"www.cosmopolitan.com", "www.esquire.com"};
 	private static final String AZURE_URL = "https://onion.azureedge.net/";
 	private static final String[] AZURE_FRONTS = new String[]{"ajax.aspnetcdn.com"};
+	private static final String CDN77_URL = "https://1314488750.rsc.cdn77.org/";
+	private static final String[] CDN77_FRONTS = new String[]{"www.phpmyadmin.net"};
 
 	@TempDir
 	private File tempFolder;
-	private File obfs4Executable;
+	private File lyrebirdExecutable;
 
 	@BeforeEach
 	public void setup() throws IOException {
-		obfs4Executable = new File(tempFolder, "obfs4Executable");
-		extractObfs4Executable();
+		lyrebirdExecutable = new File(tempFolder, "lyrebirdExecutable");
+		extractLyrebirdExecutable();
 	}
 
 	@Test
@@ -45,9 +46,14 @@ public class MoatApiTest {
 		testCn(AZURE_URL, AZURE_FRONTS);
 	}
 
+	@Test
+	public void testCnCdn77() throws Exception {
+		testCn(CDN77_URL, CDN77_FRONTS);
+	}
+
 	private void testCn(String url, String[] fronts) throws Exception {
 		for (String front : fronts) {
-			MoatApi moatApi = new MoatApi(obfs4Executable, tempFolder, url, front);
+			MoatApi moatApi = new MoatApi(lyrebirdExecutable, tempFolder, url, front);
 			List<Bridges> bridges = moatApi.getWithCountry("cn");
 			boolean anyObfs4 = false, anySnowflake = false;
 			for (Bridges b : bridges) {
@@ -69,16 +75,21 @@ public class MoatApiTest {
 		testUs(AZURE_URL, AZURE_FRONTS);
 	}
 
+	@Test
+	public void testUsCdn77() throws Exception {
+		testUs(CDN77_URL, CDN77_FRONTS);
+	}
+
 	private void testUs(String url, String[] fronts) throws Exception {
 		for (String front : fronts) {
-			MoatApi moatApi = new MoatApi(obfs4Executable, tempFolder, url, front);
+			MoatApi moatApi = new MoatApi(lyrebirdExecutable, tempFolder, url, front);
 			assertEquals(emptyList(), moatApi.getWithCountry("us"));
 		}
 	}
 
-	private void extractObfs4Executable() throws IOException {
-		OutputStream out = new FileOutputStream(obfs4Executable);
-		InputStream in = getInputStream();
+	private void extractLyrebirdExecutable() throws IOException {
+		OutputStream out = new FileOutputStream(lyrebirdExecutable);
+		InputStream in = getResourceInputStream("x86_64/lyrebird");
 		byte[] buf = new byte[4096];
 		while (true) {
 			int read = in.read(buf);
@@ -88,14 +99,7 @@ public class MoatApiTest {
 		in.close();
 		out.flush();
 		out.close();
-		if (!obfs4Executable.setExecutable(true, true)) throw new IOException();
-	}
-
-	private InputStream getInputStream() throws IOException {
-		InputStream in = getResourceInputStream("obfs4proxy_linux-x86_64.zip");
-		ZipInputStream zin = new ZipInputStream(in);
-		if (zin.getNextEntry() == null) throw new IOException();
-		return zin;
+		if (!lyrebirdExecutable.setExecutable(true, true)) throw new IOException();
 	}
 
 	@SuppressWarnings("SameParameterValue")