[턴] 안드로이드 훅 기술 이해 및 간단한 실전
훅은 영어로 번역하면'갈고리'라는 뜻인데 우리는 언제 이'갈고리'를 사용합니까?Android 운영 체제에서 시스템은 자체 이벤트 배포 메커니즘을 유지 관리합니다.응용 프로그램은 트리거 이벤트와 백엔드 논리 처리를 포함하고 이벤트 절차에 따라 한 걸음 한 걸음 아래로 실행된다.한편,'갈고리'는 사건이 종점으로 전송되기 전에 사건의 전송을 캡처하고 감시하며 갈고리에 걸린 사건처럼 사건을 연결할 때 자신의 특정한 사건을 처리할 수 있다는 뜻이다.
훅의 이 기능은 자신의 코드를 훅에 걸린 프로그램의 프로세스에 융합시켜 목표 프로세스의 일부분이 될 수 있도록 한다.API Hook 기술은 시스템의 API 함수 실행을 리디렉션하는 API 실행 결과를 변경하는 데 사용되는 기술입니다.안드로이드 시스템에서 샌드박스 메커니즘을 사용했는데 일반 사용자 프로그램의 프로세스 공간은 모두 독립되어 프로그램의 운행이 서로 방해되지 않는다.이로써 우리는 하나의 프로그램을 통해 다른 프로그램의 어떤 행위를 바꾸기를 바라는 생각은 직접적으로 실현될 수 없지만 훅의 출현은 이런 문제를 해결하는 길을 개척해 주었다.물론 훅의 대상과 훅의 후처리 방식에 따라 훅은 메시지 훅, API 훅 등 다양한 종류로 나뉜다.
2. 자주 쓰는 훅 프레임
교체를 통해/system/bin/appprocess 프로그램이 Zygote 프로세스를 제어하여 app프로세스를 시작하는 동안 XposedBridge가 로드됩니다.jar 이 Jar 패키지는 Zygote 프로세스와 생성된 Dalvik 가상 머신에 대한 납치를 완성합니다.Xposed는 전원을 켤 때 모든 훅 펀치에 대한 납치를 완료하고 원래 펀션이 실행된 전후에 사용자 정의 코드를 추가합니다.
3. Java 반사로 API Hook 구현
안드로이드 플랫폼의 가상 기기에 자바와 반사하는 방식을 주입하여 안드로이드 가상 기기에서 함수를 호출하는 방식(ClassLoader)을 바꾸어 자바 함수의 방향을 바꾸는 목적을 달성한다. 여기서 우리는 이런 조작을 자바 API Hook이라고 부른다.
다음은 훅 뷰의 OnClickListener를 통해 훅의 사용 방법을 설명합니다.
먼저 View의 set On Click Listener 방법에 들어가서 우리는 On Click Listener 대상이 Listener Info라는 내부 클래스에 저장된 것을 보았다. 그 중에서 mListener Info는 View의 구성원 변수이다.Listene Info에는 View의 각종 감청 사건, 예를 들면 On Click Listener, On Long Click Listener, On Key Listener 등이 저장되어 있다.
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
우리의 목표는 Hook On Click Listener이기 때문에 View에 감청 이벤트를 설정한 후 On Click Listener 대상을 교체하고 사용자 정의 조작을 주입해야 합니다.
private void hookOnClickListener(View view) {
try {
// View ListenerInfo
Method getListenerInfo = View.class.getDeclaredMethod("getListenerInfo");
getListenerInfo.setAccessible(true);
Object listenerInfo = getListenerInfo.invoke(view);
// OnClickListener
Class> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");
Field mOnClickListener = listenerInfoClz.getDeclaredField("mOnClickListener");
mOnClickListener.setAccessible(true);
View.OnClickListener originOnClickListener = (View.OnClickListener) mOnClickListener.get(listenerInfo);
// OnClickListener OnClickListener
View.OnClickListener hookedOnClickListener = new HookedOnClickListener(originOnClickListener);
mOnClickListener.set(listenerInfo, hookedOnClickListener);
} catch (Exception e) {
log.warn("hook clickListener failed!", e);
}
}
class HookedOnClickListener implements View.OnClickListener {
private View.OnClickListener origin;
HookedOnClickListener(View.OnClickListener origin) {
this.origin = origin;
}
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "hook click", Toast.LENGTH_SHORT).show();
log.info("Before click, do what you want to to.");
if (origin != null) {
origin.onClick(v);
}
log.info("After click, do what you want to to.");
}
}
여기까지, 우리는 OnClickListener에 성공했습니다. 클릭하기 전과 클릭한 후에 어떤 조작을 실행할 수 있고 우리의 목적을 달성할 수 있습니다.다음은 호출된 부분입니다. Button에 OnClickListener를 설정한 후 훅 동작을 실행합니다.버튼을 클릭하면 로그의 인쇄 결과는: Before click → onClick → After click입니다.
Button btnSend = (Button) findViewById(R.id.btn_send);
btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
log.info("onClick");
}
});
hookOnClickListener(btnSend);
4. 훅으로 앱 내 알림 차단
응용 프로그램에 많은 SDK가 접속되면 SDK 내부에서 시스템 서비스인 Notification Manager를 사용하여 알림을 보내기 때문에 알림을 관리하고 제어하기 어렵다.현재 우리는 훅 기술로 일부 알림을 차단하고 응용 내의 알림 발송 조작을 제한한다.
알림을 보내는 방법은 Notification Manager의 notify 방법입니다. API를 따라 들어가 보겠습니다.INotification Manager 유형의 객체를 사용하고 enqueueNotification WithTag 방법을 사용하여 알림 전송을 완료합니다.
public void notify(String tag, int id, Notification notification)
{
INotificationManager service = getService();
…… //
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
stripped, idOut, UserHandle.myUserId());
if (id != idOut[0]) {
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
}
} catch (RemoteException e) {
}
}
private static INotificationManager sService;
/** @hide */
static public INotificationManager getService()
{
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService("notification");
sService = INotificationManager.Stub.asInterface(b);
return sService;
}
Inotification Manager는 크로스 프로세스 통신의 Binder 클래스이고 sService는 NMS(Notification Manager Service)가 클라이언트의 에이전트로 sService에 위탁하여 NMS에 전달하는 통지를 보낸다. 구체적인 원리는 여기서 더 이상 자세히 연구하지 않고 시스템 서비스와 응용의 통신 과정을 이해할 수 있다.
SService는 정적 구성원 변수이며 한 번만 초기화됩니다.SService를 사용자 정의로 바꾸면 되잖아요. 그렇죠.다음은 대량의 자바 반사와 동적 에이전트를 사용하는데 특히 코드의 작성에 주의해야 한다.
private void hookNotificationManager(Context context) {
try {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// sService
Method getService = NotificationManager.class.getDeclaredMethod("getService");
getService.setAccessible(true);
final Object sService = getService.invoke(notificationManager);
Class iNotiMngClz = Class.forName("android.app.INotificationManager");
// INotificationManager
Object proxyNotiMng = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{iNotiMngClz}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.debug("invoke(). method:{}", method);
if (args != null && args.length > 0) {
for (Object arg : args) {
log.debug("type:{}, arg:{}", arg != null ? arg.getClass() : null, arg);
}
}
// sService ,
// return method.invoke(sService, args);
// ,
return null;
// Tag ID
}
});
// sService
Field sServiceField = NotificationManager.class.getDeclaredField("sService");
sServiceField.setAccessible(true);
sServiceField.set(notificationManager, proxyNotiMng);
} catch (Exception e) {
log.warn("Hook NotificationManager failed!", e);
}
}
Hook의 시기는 가능한 한 빨라야 합니다. 우리는attachBaseContext에서 조작합니다.
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
hookNotificationManager(newBase);
}
이렇게 해서 우리는 알림에 대한 차단을 완성했다. 이를 통해 알 수 있듯이 훅 기술은 정말 강하다. 많은 플러그인화의 원리는 훅 위에 세워진 것이다.
요약:
참고 자료:
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.