Posts Tagged ‘android’

Build Android Clang Toolchain

2017/11/16

This document describes how to build the clang toolchain included in Android NDK from source. The official documentation doesn’t work for me: https://android.googlesource.com/platform/external/clang/+/dev/ToolchainPrebuilts.md

Step 1: Download NDK binary

Go to Google website to download NDK binary for Linux. We only need the repo.prop file to know the exact commit in the source repo. It’s in NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64/repo.prop.
This documentation is correct for both NDK r15c and r16.

Step 2: Download toolchain source from AOSP repo

repo init -u https://android.googlesource.com/platform/manifest -b llvm
repo sync

Step 3: Checkout the exact version as in NDK

You can manually go to each project directory and do `git checkout <commit>`, where “<commit>” is listed in repo.prop.
You can also use the following checkoutall.sh script. To run, go to the root dir and run `bash checkoutall.sh /path/to/repo.prop`

#!/bin/bash

if [ $# -ne 1 ] ; then
	echo usage: bash checkoutall.sh repo.prop
	exit
fi
prop=$1
if [ '!' -f $prop ] ; then
	echo $prop doesnt exist
	exit
fi
if [ '!' -f .repo/project.list ] ; then
	echo not in aosp dir
	exit
fi

repo list > tmp1

aosp=`pwd`
for i in `cut -d ' ' -f 1 "$prop"` ; do
	commit=`grep "^$i " "$prop" | cut -d ' ' -f 2`
	path=`grep " : $i$" tmp1 | sed -e 's/ .*//'`
	if [ -z "$path" ] ; then
		echo "Warning: $i not found"
		continue
	fi
	if [ '!' -d "$path" ] ; then
		echo "Warning: $path not exist"
		continue
	fi
	cd $path
	git checkout -q $commit
	cd $aosp
done

Step 4: symlink bootstrap.bash

ln -s build/soong/bootstrap.bash ./

Step 5: Patch prebuilts/sdk

There are some version mismatches between prebuilts/sdk and soong.

diff --git a/tools/Android.bp b/tools/Android.bp
index 6f2d1ac..6ed1c8f 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -2,7 +2,7 @@ cc_prebuilt_library_shared {
     name: "libLLVM",
     host_supported: true,
     target: {
-        linux_glibc_x86_64: {
+        linux_x86_64: {
             srcs: ["linux/lib64/libLLVM.so"],
         },
         darwin_x86_64: {
@@ -21,7 +21,7 @@ cc_prebuilt_library_shared {
     name: "libclang",
     host_supported: true,
     target: {
-        linux_glibc_x86_64: {
+        linux_x86_64: {
             srcs: ["linux/lib64/libclang.so"],
         },
         darwin_x86_64: {
@@ -35,8 +35,3 @@ cc_prebuilt_library_shared {
         }
     },
 }
-
-java_import {
-    name: "sdk-core-lambda-stubs",
-    jars: ["core-lambda-stubs.jar"],
-}

Step 6: Patch build/soong

The soong version listed in repo.prop seems to be too old for the header-abi-linker tool. We need to apply the following patch: https://android.googlesource.com/platform/build/soong/+/6ab3d846b29898be468d374a99ef11c58bdd8d3e

diff --git a/cc/builder.go b/cc/builder.go
index 51c4ce9..2f95006 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -170,12 +170,12 @@ var (
 
 	sAbiLink = pctx.AndroidStaticRule("sAbiLink",
 		blueprint.RuleParams{
-			Command:        "$sAbiLinker -o ${out} $symbolFile -arch $arch -api $api $exportedHeaderFlags @${out}.rsp ",
+			Command:        "$sAbiLinker -o ${out} $symbolFilter -arch $arch -api $api $exportedHeaderFlags @${out}.rsp ",
 			CommandDeps:    []string{"$sAbiLinker"},
 			Rspfile:        "${out}.rsp",
 			RspfileContent: "${in}",
 		},
-		"symbolFile", "arch", "api", "exportedHeaderFlags")
+		"symbolFilter", "arch", "api", "exportedHeaderFlags")
 
 	_ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-diff")
 
@@ -613,14 +613,17 @@ func TransformObjToDynamicBinary(ctx android.ModuleContext,
 
 // Generate a rule to combine .dump sAbi dump files from multiple source files
 // into a single .ldump sAbi dump file
-func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths,
+func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path,
 	symbolFile android.OptionalPath, apiLevel, baseName, exportedHeaderFlags string) android.OptionalPath {
 	outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
-	var symbolFileStr string
+	var symbolFilterStr string
 	var linkedDumpDep android.Path
 	if symbolFile.Valid() {
-		symbolFileStr = "-v " + symbolFile.Path().String()
+		symbolFilterStr = "-v " + symbolFile.Path().String()
 		linkedDumpDep = symbolFile.Path()
+	} else {
+		linkedDumpDep = soFile
+		symbolFilterStr = "-so " + soFile.String()
 	}
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
 		Rule:        sAbiLink,
@@ -629,9 +632,9 @@ func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Path
 		Inputs:      sAbiDumps,
 		Implicit:    linkedDumpDep,
 		Args: map[string]string{
-			"symbolFile": symbolFileStr,
-			"arch":       ctx.Arch().ArchType.Name,
-			"api":        apiLevel,
+			"symbolFilter": symbolFilterStr,
+			"arch":         ctx.Arch().ArchType.Name,
+			"api":          apiLevel,
 			"exportedHeaderFlags": exportedHeaderFlags,
 		},
 	})
diff --git a/cc/library.go b/cc/library.go
index 997344c..0164221 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -589,12 +589,12 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext,
 	objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...)
 
 	library.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, library.getLibName(ctx))
-	library.linkSAbiDumpFiles(ctx, objs, fileName)
+	library.linkSAbiDumpFiles(ctx, objs, fileName, ret)
 
 	return ret
 }
 
-func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string) {
+func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
 	//Also take into account object re-use.
 	if len(objs.sAbiDumpFiles) > 0 && ctx.createVndkSourceAbiDump() && !ctx.Vendor() {
 		refSourceDumpFile := android.PathForVndkRefAbiDump(ctx, "current", fileName, vndkVsNdk(ctx), true)
@@ -612,7 +612,7 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objec
 			SourceAbiFlags = append(SourceAbiFlags, reexportedInclude)
 		}
 		exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
-		library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, symbolFile, "current", fileName, exportedHeaderFlags)
+		library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, symbolFile, "current", fileName, exportedHeaderFlags)
 		if refSourceDumpFile.Valid() {
 			unzippedRefDump := UnzipRefDump(ctx, refSourceDumpFile.Path(), fileName)
 			library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(), unzippedRefDump, fileName)

Step 7: Build

Run `python external/clang/build.py`

Advertisements

Modifying Android APKs which does self certificate checking

2016/07/13

When I modify an Android app which is not mine, I use apktool to unpack the APK, modify the smali, use apktool to pack it and finally sign it using my own key. This works for most of the Apps. However, some Apps explicitly perform certificate checking in their code. The following code snippet illustrates such checking:

PackageManager pm = myContext.getPackageManager();
PackageInfo info = pm.getPackageInfo("my.package.name", PackageManager.GET_SIGNATURES);
String expectedSig = "308203a5...";
if (!expectedSig.equals(info.signatures[0].toCharsString()) {
  quit();
}

One way to fix this is by removing the “if” block, but it’s difficult to locate all such if blocks, especially in smali. A more convenient way is to hook the PackageManager.getPackageInfo() API and change info.signatures to the original APK’s signature. The following code snippet illustrates such hooking:

PackageManager pm = myContext.getPackageManager();
PackageInfo info = PatchSignature.getPackageInfo(pm, "my.package.name", PackageManager.GET_SIGNATURES);
...
public class PatchSignature {
  public static PackageInfo getPackageInfo (PackageManager pm, String packageName, int flags) throws PackageManager.NameNotFoundException
  {
    PackageInfo info = pm.getPackageInfo(packageName, flags);
    if ("my.package.name".equals(packageName) &&
        info.signatures != null && info.signatures.length > 0 &&
        info.signatures[0] != null)
      info.signatures[0] = new Signature("308203b6...");
    return info;
  }
}

Three things need to be done here:

  1. Change all PackageManager.getPackageInfo() to PatchSignature.getPackageInfo().
  2. Add class PatchSignature.
  3. Find out the correct signature.

It is very easy to locate and replace all PackageManager.getPackageInfo() calls in the smali code. All we need to do is replacing:

invoke-virtual {PARAM1, PARAM2, PARAM3}, Landroid/content/pm/PackageManager;->getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;

with

invoke-static {PARAM1, PARAM2, PARAM3}, LPatchSignature;->getPackageInfo(Landroid/content/pm/PackageManager;Ljava/lang/String;I)Landroid/content/pm/PackageInfo;

The smali code for PatchSignature can be easily obtained by writing a simple app with the java code and disassemble it. Now we have only one problem remaining, how to obtain the original certificate? I.e. what should we put in new Signature("...")?

Here’s what I found the most convenient way:

openssl pkcs7 -inform DER -print_certs -in unpacked-app-using-apktool/original/META-INF/CERT.RSA | openssl x509 -inform PEM -outform DER | xxd -p