Android 는 루트 없 이 apk 의 침묵 설 치 를 실현 합 니 다.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
그러나 이것 은 진정 으로 침묵 설 치 를 실현 하지 못 했다.사용자 인터페이스 가 있 기 때문에 사용자 가 알 게 될 것 이다.그렇다면 어떻게 백 스테이지 에 몰래 APK 를 설치 할 수 있 을 까?안 드 로 이 드 시스템 의 소스 코드 가 정상적으로 APK 를 설치 하 는 과정 을 보 려 고 할 수 밖 에 없습니다.제 가 다운로드 한 소스 코드 는 안 드 로 이 드 5.0 시스템 의 5 개의 G 크기 입 니 다.그러나 안 드 로 이 드 5.0 은 안전 한 업데이트 가 있 기 때문에 이전 버 전과 어느 정도 차이 가 있 습 니 다.하지만 하 나 를 배 운 후에 다른 비슷 한 과정 을 배 우 는 것 은 간단 합 니 다.C 언어 를 배 운 것 처럼 자바 도 어렵 지 않다.Android 시스템 은 모든 Permission(권한)을 잠재 적 위험 에 따라'normal','dangerous','signature','signature OrSystem'등 네 가지 등급 으로 구분한다.APK 의 설치 에 대응 하 는 권한 은 INSTALL 입 니 다.PACKAGES,권한 등급 은 다음 두 가지 에 속 합 니 다.따라서 최종 적 으로 APK 의 침묵 설 치 를 실현 하려 면 특별한 처리 가 필요 합 니 다.설 치 된 이 프로 세 스 를 실행 하려 면 시스템 프로 세 스 가 필요 합 니 다.
그렇다면 안 드 로 이 드 자체 가 APK 설 치 를 어떻게 실현 하 는 지 살 펴 보 자.설 치 된 명령 은 pm install 입 니 다.시스템 소스 코드 의/framework s/base/cmds/pm/src/com/android/commands/pm/pm.자바 라 는 파일 을 찾 았 습 니 다.그 는 pm 명령 을 실 현 했 습 니 다.runInstall 방법 을 보 았 습 니 다.이것 이 바로 APK 의 설치 과정 입 니 다.
private void runInstall() {
int installFlags = 0;
int userId = UserHandle.USER_ALL;
String installerPackageName = null;
String opt;
String originatingUriString = null;
String referrer = null;
String abi = null;
while ((opt=nextOption()) != null) {
if (opt.equals("-l")) {
installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
} else if (opt.equals("-r")) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
} else if (opt.equals("-i")) {
installerPackageName = nextOptionData();
if (installerPackageName == null) {
System.err.println("Error: no value specified for -i");
return;
}
} else if (opt.equals("-t")) {
installFlags |= PackageManager.INSTALL_ALLOW_TEST;
} else if (opt.equals("-s")) {
// Override if -s option is specified.
installFlags |= PackageManager.INSTALL_EXTERNAL;
} else if (opt.equals("-f")) {
// Override if -s option is specified.
installFlags |= PackageManager.INSTALL_INTERNAL;
} else if (opt.equals("-d")) {
installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
} else if (opt.equals("--originating-uri")) {
originatingUriString = nextOptionData();
if (originatingUriString == null) {
System.err.println("Error: must supply argument for --originating-uri");
return;
}
} else if (opt.equals("--referrer")) {
referrer = nextOptionData();
if (referrer == null) {
System.err.println("Error: must supply argument for --referrer");
return;
}
} else if (opt.equals("--abi")) {
abi = checkAbiArgument(nextOptionData());
} else if (opt.equals("--user")) {
userId = Integer.parseInt(nextOptionData());
} else {
System.err.println("Error: Unknown option: " + opt);
return;
}
}
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_OWNER;
installFlags |= PackageManager.INSTALL_ALL_USERS;
}
final Uri verificationURI;
final Uri originatingURI;
final Uri referrerURI;
if (originatingUriString != null) {
originatingURI = Uri.parse(originatingUriString);
} else {
originatingURI = null;
}
if (referrer != null) {
referrerURI = Uri.parse(referrer);
} else {
referrerURI = null;
}
// Populate apkURI, must be present
final String apkFilePath = nextArg();
System.err.println("\tpkg: " + apkFilePath);
if (apkFilePath == null) {
System.err.println("Error: no package specified");
return;
}
// Populate verificationURI, optionally present
final String verificationFilePath = nextArg();
if (verificationFilePath != null) {
System.err.println("\tver: " + verificationFilePath);
verificationURI = Uri.fromFile(new File(verificationFilePath));
} else {
verificationURI = null;
}
LocalPackageInstallObserver obs = new LocalPackageInstallObserver();
try {
VerificationParams verificationParams = new VerificationParams(verificationURI,
originatingURI, referrerURI, VerificationParams.NO_UID, null);
mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags,
installerPackageName, verificationParams, abi, userId); // !!
synchronized (obs) {
while (!obs.finished) {
try {
obs.wait();
} catch (InterruptedException e) {
}
}
if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
System.out.println("Success");
} else {
System.err.println("Failure ["
+ installFailureToString(obs)
+ "]");
}
}
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
}
}
이 과정 을 알 게 된 후에 어떻게 해 야 할 지 대충 알 게 되 었 다.시스템 밑바닥 에서 이 API 를 차단 한 이상 이 차단 을 돌아 서 사용 할 방법 을 생각해 보 세 요.먼저 떠 오 르 는 것 은 AIDL 을 사용 하 는 것 입 니 다.AIDL 이라는 것 을 모 르 는 도 모 에 게 먼저 물 어보 세 요~~위의 코드 에서 최종 적 으로 설 치 를 실현 한 다 는 말 입 니 다.mPm.intallPackage AsUser(...),mPm 은 무엇 입 니까?IPackageManager 유형 을 발견 하기 어렵 지 않 습 니 다.그러면 이 종 류 는 어디에서 나 옵 니까?찾 아 보 세 요./framework s/base/core/java/android/content/pm 이 가방 밑 에 있 습 니 다.우리 프로젝트 디 렉 터 리 밑 에 복사 하면 가방 이름 이 바 뀌 지 않 습 니 다.이 파일 만 복사 하면 안 될 것 입 니 다.다른 에 이 드 를 찾 을 수 없 으 면 복사 해 올 것 입 니 다.안 드 로 이 드 5.0 에서 에 이 드 가 바 뀌 는 것 이 비교적 크기 때문에 많은 것 을 복사 해 야 하고 변경 도 해 야 한다.나 도 그 가 잘못 보고 하지 않 은 것 으로 바 꾸 는 데 오 랜 시간 이 걸 렸 다.최종 프로젝트 목록 은 다음 과 같 습 니 다~~
그렇다면 어떻게 사용 할 까?
4.567917.1.시스템 서비스 android.os.ServiceManager 를 먼저 가 져 옵 니 다.이것 은 또 숨겨 진 것 입 니 다.어떻게 합 니까?자바 수준 을 시험 할 때 가 왔 습 니 다~~맞습니다.반사 메커니즘 으로 ServiceManager 클래스 와 이 클래스 의 방법 을 얻 습 니 다.
4.567917.2.서비스 가 있 으 면 우 리 는 IPackage Manager 라 는 대상 을 받 아야 한다.
4.567917.3.IPackageManager 안의 installPackage 방법 으로 설치 합 니 다.
구현 코드 는 다음 과 같 습 니 다:
package com.example.autoinstall;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageManager;
import android.content.pm.VerificationParams;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* Button
* @param view
*/
public void install(View view)
{
String path = "";
if (FileUtils.isSdcardReady()) {
path = FileUtils.getSdcardPath();
} else {
path = FileUtils.getCachePath(this);
}
String fileName = path + "/AidlServerDemo.apk";
File file = new File(fileName);
try {
if(!file.exists())
copyAPK2SD(fileName);
Uri uri = Uri.fromFile(new File(fileName));
// Java android.os.ServiceManager
Class<?> clazz = Class.forName("android.os.ServiceManager");
Method method = clazz.getMethod("getService", String.class);
IBinder iBinder = (IBinder) method.invoke(null, "package");
IPackageManager ipm = IPackageManager.Stub.asInterface(iBinder);
@SuppressWarnings("deprecation")
VerificationParams verificationParams = new VerificationParams(null, null, null, VerificationParams.NO_UID, null);
// ( , )
ipm.installPackage(fileName, new PackageInstallObserver(), 2, null, verificationParams, "");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//
class PackageInstallObserver extends IPackageInstallObserver2.Stub {
@Override
public void onUserActionRequired(Intent intent) throws RemoteException {
// TODO Auto-generated method stub
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg, Bundle extras) throws RemoteException {
//returnCode<span style="font-family: Arial, Helvetica, sans-serif;"> 1, </span>
}
};
/**
* assets APK SD
*
* @param strOutFileName
* @throws IOException
*/
private void copyAPK2SD(String strOutFileName) throws IOException {
FileUtils.createDipPath(strOutFileName);
InputStream myInput = this.getAssets().open("AidlServerDemo.apk");
OutputStream myOutput = new FileOutputStream(strOutFileName);
byte[] buffer = new byte[1024];
int length = myInput.read(buffer);
while (length > 0) {
myOutput.write(buffer, 0, length);
length = myInput.read(buffer);
}
myOutput.flush();
myInput.close();
myOutput.close();
}
}
각 버 전의 시스템 소스 코드 에 있 는 adl 이 다 를 수 있 으 므 로 구체 적 으로 호출 하 는 방법 과 파 라 메 터 는 실제 상황 에 따라 정 해 야 합 니 다.Pm.자바 라 는 파일 의 소스 코드 를 자세히 읽 어야 합 니 다.다른 버 전에 서 는 이 네 개의 파일 만 복사 할 수 있 습 니 다:PackageManager.java,IPackageDeleteObserver.aidl,IPackagerInstallObserver.aidl,IPackageMoveObserver.aidl
그리고 설정 목록 파일 에 INSTALL 을 추가 해 야 합 니 다.PACKAGE 권한
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
그리고 이 응용 uid 를 시스템 단계 로 설정 하고 manifest 탭 에 다음 속성 을 추가 합 니 다.
android:sharedUserId="android.uid.system"
이렇게 만 하면 침묵 설 치 를 실현 할 수 없습니다.시스템 은 이 app 이 시스템 등급 의 응용 이 라 고 생각 하지 않 기 때문에 이 응용 프로그램의 APK 에 시스템 서명 을 해 야 합 니 다.(주의:침묵 설 치 된 APK 가 아니 라 침묵 설 치 를 실현 하 는 APK 입 니 다.)서명 과정 은 다음 과 같 습 니 다.총 세 개의 파일 이 필요 합 니 다.
java -jar SignApk.jar platform.x509.pem platform.pk8 AutoInstall.apk AutoInstall_new.apk
이후,서명 한 APK 를 휴대폰 에 설치 하고,켜 고,침묵 설 치 를 클릭 하고,프로그램 페이지 를 찾 아 보 니 설치 에 성 공 했 습 니 다~~
더 많은 내용 은 주 제 를 참고 하여 학습 할 수 있다.
본 고 는 주로 침묵 설 치 를 실현 하 는 방향 을 제 공 했 지만 구체 적 으로 각 시스템 을 어떻게 호 환 하 는 지 하 나 를 보면 열 을 안다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.