Dji Mimo APP逆向.1(pocket 2直播模式+物体追踪)

大疆的东西,我真的太喜欢了。。。喜欢到想看看是如何做出来的。

逆向菜鸡,安卓羸弱,反正就是个看热闹的主,大佬们轻点拍~

这个就是将应用退壳的东西

具体是一个梆梆企业版的壳子,我是在真机上面把壳砸了的

大概就是在运行前,需要从壳里面把真正的应用解压出来,然后我们从内存里面把这个dump出来,因为是一个完整的调用链条,然后再组装回来~~~~

https://mydown.yesky.com/pcsoft/413552646.html

当然了,这个东西是可以解压的

算了,本来想展示点别的东西,这个电脑不合适,看源码吧


其实java还好一点,反编译的源码还有点难懂,C#完全就是源码。。。

一个是R文件的解析,在安卓的世界里面各种资源都是要被打包到R文件里面的,所以你看到的是一个这样的反编译的资源文件

我推测,对于一些控制类的操作是用json打包发送的

视频流+控制“流”

Google分析的组件,毕竟作为国际大厂,出海是必然的

二维码的组件,作为一些登录时使用

第二个jar文件,我推测是给poctek 2代的直播流写的模块

你看这个是虎牙直播的组件

public UUID getUUId() { return this.uuid; }
public boolean isEmpty() { return this.raw.isEmpty(); }

可以点进去仔细的看,这里的包没有混淆

这里是dji的实现,让我稍微看看是什么东西

package com.dji.socialsdkwx.login.wechat;
import android.content.Intent;import android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;import com.tencent.mm.opensdk.modelbase.BaseReq;import com.tencent.mm.opensdk.modelbase.BaseResp;import com.tencent.mm.opensdk.openapi.IWXAPI;import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
public class SocialWeChatActivity extends AppCompatActivity implements IWXAPIEventHandler { private IWXAPI api;
/* access modifiers changed from: protected */ public void onCreate(Bundle bundle) { }
/* access modifiers changed from: protected */ public void onNewIntent(Intent intent) { }
public void onReq(BaseReq baseReq) { }
public void onResp(BaseResp baseResp) { }}
import com.tencent.mm.opensdk.modelbase.BaseReq;import com.tencent.mm.opensdk.modelbase.BaseResp;import com.tencent.mm.opensdk.openapi.IWXAPI;import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;

你看这个,其实是微信的登录接口,至于其它的可能要设置语言才可以打开

package com.dji.livestream.livetype;
import android.app.Dialog;import android.content.Intent;import android.os.Handler;import android.os.Looper;import android.view.View;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import androidx.appcompat.app.AppCompatActivity;

import com.dji.device.util.c;import com.dji.livestream.R;import com.dji.livestream.bean.DJILiveLoadingStage;import com.dji.livestream.bean.b;import com.dji.livestream.livetype.-$;import com.dji.livestream.livetype.a;import com.dji.livestream.page.LiveStreamBaseActivity;import dji.base.ui.thirdparty.permission.CommonPermissionHelper;

import org.greenrobot.eventbus.ThreadMode;import org.greenrobot.eventbus.l;

这里的安卓库分为三类,原生的安卓构件,dji自己的库

以及使用的三方库

EventBus的特性包括:

 简化了组件间的通讯

 分离了事件的发送者和接受者;

 在Activity、Fragment和线程中表现良好;

 避免了复杂的和易错的依赖关系和声明周期问题;

 使得代码更简洁;

 更快;

 更小(约50k的jar包)

 实际上超过1亿的app证明了它的性能;

 有高级属性,例如发布线程、订阅属性等。

可以看到有很多新的软件库在里面,比如全新的储存管理

以及有很多的广播接收器,Facebook,HW

看,HW的推送库

以及全新的安卓库

干哦兄弟!

原生C++

以及FFmpeg的解码库

以及人脸追踪???是用的这种东西吗

private final String[] PERMISSIONS = {"android.permission.BLUETOOTH", "android.permission.BLUETOOTH_ADMIN", "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION"};// permissions={blue,blue_admin,access_file_location,access_coarse_location} private final int REQUEST_CODE_LIVE_SETTINGS = 1011; // request_code_live_settings

这里的代码做了一点识别,可以看到要动态申请的权限是蓝牙的

private Dialog confirmDialog; private com.dji.device.common.a connectHelper; private View facebookLive; private View facebookSelectedIcon; private Handler handler = new Handler(Looper.getMainLooper()); private View huyaLive; private View huyaSelectedIcon; private View kuaiShouLive; private View kuaiShouSelectedIcon; private CommonPermissionHelper permissionHelper; private CommonPermissionHelper.a permissionRequestData; private a.b presenter; private View rtmpLive; private View rtmpSelectedIcon;

在看这些函数就很有趣了,有连接大疆相机时候的指引,脸书的直播,虎牙的直播,快手的直播,以及支持自定义的RTMP直播

import com.dji.device.connect.bean.c;
package com.dji.network.bean;import com.google.gson.annotations.SerializedName;public class BaseBean extends BaseSerializable { @SerializedName("code") protected int code; @SerializedName("msg") protected String msg;
public int getCode() { return this.code; }
public String getMsg() { return this.msg; }
public void setCode(int i) { this.code = i; }
public void setMsg(String str) { this.msg = str; }}

基本可序列化???

这里是小米的推送包

public String dataPlatform() { return "XiaoMi Push"; }

OkHttp 是一个高效的 HTTP 客户端,具有非常多的优势:

  1. 能够高效的执行 http,数据加载速度更快,更省流量

  2. 支持 GZIP 压缩,提升速度,节省流量

  3. 缓存响应数据,避免了重复的网络请求

  4. 使用简单,支持同步阻塞调用和带回调的异步调用

Retrofit2简单的说就是一个网络请求的适配器,它将一个基本的Java接口通过动态代理的方式翻译成一个HTTP请求,并通过OkHttp去发送请求。

Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。

https://djigo-hk.djiservice.org

不鸟我

Osmo Shield Domain
package com.dji.pano.osmo.mobile;
import com.dji.pano.osmo.mobile.b;
class b$1 implements b.a { final /* synthetic */ b a;
b$1(b bVar) { this.a = bVar; }
public void a() { }
public void a(int i, String str) { this.a.a(i, str); }
public void a(String str) { }
public void b() { }
public void c() { }}

implements是一个类实现一个接口用的关键字 ,他是用来实现接口中定义的抽象方法。比如:people是一个接口,他里面有say这个方法。public interface people(){ public say();}但是接口没有方法体。只能通过一个具体的类去实现其中的方法体。比如chinese这个类,就实现了people这个接口。public class chinese implements people{ public say() {System.out.println("你好!");}}

https://github.com/square/wire
public RootData(Integer num, EncryptionType encryptionType, PlatformType platformType, String str, Integer num2, Integer num3, ByteString byteString, String str2, Integer num4, String str3, ByteString byteString2) { super(a, byteString2); this.version = num; this.encryption = encryptionType; this.platform = platformType; this.app_key = str; this.app_version = num2; this.plaintext_len = num3; this.content = byteString; this.cmd = str2; this.timestamp = num4; this.signature = str3; }

这个是一个协议的实现我没有细研究,直接贴上来

package com.dji.tracking.jnienum;
public enum CameraFace { LTSOT_FRONT_CAMERA(1),    // ltsot_front_camera LTSOT_BEHIND_CAMERA(2); public final int value;
private CameraFace(int i) { this.value = i; }}

这个是关于脸部追踪的代码

package com.dji.tracking.jnienum;
public enum CheckedObjectType { ML_OBJ_OTHER(0, "其他"), ML_OBJ_HEAD_SHOULDER(1, "头肩"), ML_OBJ_PERSON(2, "人"), ML_OBJ_FACE(5, "脸"), ML_OBJ_PET(6, "宠物"), ML_OBJ_GESTURE_PALM(101, "手掌"), ML_OBJ_GESTURE_VICTORY(102, "V型手势"), ML_OBJ_GESTURE_OTHER(103, "其他手势"), ML_OBJ_NONE(-1, "NONE"); public final String tip; public final int value;
private CheckedObjectType(int i, String str) { this.value = i; this.tip = str; }
public static CheckedObjectType a(int i) { CheckedObjectType[] values = values(); for (CheckedObjectType checkedObjectType : values) { if (checkedObjectType.value == i) { return checkedObjectType; } } return ML_OBJ_NONE; }}

物体识别

package com.dji.tracking.jinout;
import androidx.core.util.Pools;
public class TrackingBox { private static Pools.SynchronizedPool<TrackingBox> sPool = new Pools.SynchronizedPool<>(10); public float centerX; public float centerY; public float height; public float width;
public static TrackingBox obtain() { TrackingBox trackingBox = (TrackingBox) sPool.acquire(); return trackingBox != null ? trackingBox : new TrackingBox(); }
public void recycle() { sPool.release(this); }}

绘制一个追踪的盒子

package com.dji.tracking.jnienum;
public enum RotateAngle { ML_ROTATE_0(0), ML_ROTATE_90_CLOCKWISE(1), ML_ROTATE_180(2), ML_ROTATE_90_COUNTERCLOCKWISE(3); public final int value;
private RotateAngle(int i) { this.value = i; }}

旋转的角度

package com.dji.tracking.jnienum;
import androidx.collection.SparseArrayCompat;
public enum TrackingMode { TK_MODE_UNFUSED(-1), TK_MODE_LOST(0), TK_MODE_TRACKED(1), TK_MODE_NOT_CONFIDENT(2), TK_MODE_REDETECTED(3), TK_MODE_GESTURE_STOP(4), TK_MODE_REAL_LOST(5); private static final SparseArrayCompat<TrackingMode> h = new SparseArrayCompat<>(); public final int value;
private TrackingMode(int i2) { this.value = i2; }
public static TrackingMode a(int i2) { TrackingMode trackingMode = (TrackingMode) h.get(i2); if (trackingMode == null) { TrackingMode[] values = values(); int length = values.length; int i3 = 0; while (true) { if (i3 >= length) { break; } TrackingMode trackingMode2 = values[i3]; if (trackingMode2.value == i2) { trackingMode = trackingMode2; break; } i3++; } if (trackingMode == null) { trackingMode = TK_MODE_UNFUSED; } h.put(i2, trackingMode); } return trackingMode; }}

追踪模式

package com.dji.tracking;
import android.os.Build;import com.dji.tracking.a.a;import com.dji.tracking.a.b;
/* access modifiers changed from: package-private */public class g { private static final String[] a = {"HUAWEI ANE", "HONOR STF"};
static f a() { String upperCase = String.format("%s %s", Build.BRAND, Build.MODEL).toUpperCase(); for (String str : a) { if (upperCase.contains(str)) { return new a(); } } return new b(); }}

这个不知道是为什么,单独的说了华为,大写?

最后看看这个,video里面有什么

package com.dji.video.codec;
import android.media.MediaCodec;import com.dji.video.stream.AACFrameDelegate;import com.dji.video.stream.AudioConfigs;import com.dji.video.utils.c;import java.nio.ByteBuffer;import java.util.UUID;
import java.util.UUID;
public class AudioStreamDecoder { private final int a = 0; private final int b = 1; private final int c = 3; private int d = 0; private MediaCodec e; private ByteBuffer[] f; private ByteBuffer[] g; private boolean h; private boolean i = false; private long j = 0; private final int k = 16384; private c l = new c(64, 16384); private byte[] m = new byte[16384]; private a n; private AudioConfigs o; private UUID p; private AACFrameDelegate q; private boolean r = false;
class a extends Thread { private boolean b = false;
a() { }
public void run() { } }

音频解码类

package com.dji.video.codec;
import com.dji.video.codec.MediaCodecDecoder;import com.dji.video.edit.MvModel;import java.util.ArrayList;import java.util.Hashtable;import java.util.List;
public class c { public static List<MediaCodecDecoder.a> a = new ArrayList(); public static Hashtable<String, MediaCodecDecoder.b> b = new Hashtable<>();
public static void a(ArrayList<MvModel> arrayList) { if (arrayList != null) { if (a.size() > 0) { a.clear(); } if (b.size() > 0) { b.clear(); } for (int i = 0; i < arrayList.size(); i++) { MvModel mvModel = arrayList.get(i); if (mvModel.d() == 1) { MediaCodecDecoder.b bVar = new MediaCodecDecoder.b(); String b2 = mvModel.b(); bVar.a = mvModel.e(); bVar.b = mvModel.f(); bVar.d = mvModel.g(); bVar.c = (int) (mvModel.h() + mvModel.c()); if (!b.containsKey(b2)) { b.put(b2, bVar); } else if (b.get(b2).c < bVar.c) { b.put(b2, bVar); } } } } }}

推测这个是视频编辑功能里面的一个子功能

下面的代码有这个库 


 MediaCodec类可用于访问Android底层的多媒体编解码器,例如,编码器/解码器组件。它是Android底层多媒体支持基础架构的一部分(通常与MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface, 以及AudioTrack一起使用)。


import android.media.MediaCodec;import android.media.MediaCodecInfo;import android.media.MediaCodecList;import android.media.MediaExtractor;import android.media.MediaFormat;
package com.dji.video.codec;
import android.media.MediaCodec;import android.media.MediaCodecInfo;import android.media.MediaCodecList;import android.media.MediaExtractor;import android.media.MediaFormat;import android.os.Build;import java.io.File;import java.io.IOException;import java.util.List;import junit.framework.Assert;
public class e { public class a { private c b;
public a(c cVar) { this.b = cVar; }
private void a(int i) throws Exception { }
public void a() throws Exception { } }
public class b { private c b;
public b(c cVar) { this.b = cVar; }
private void a(MediaExtractor mediaExtractor, int i, MediaCodec mediaCodec) throws Exception { }
public void a() throws Exception { } }
public class c { int a = 0; boolean b = false; boolean c = false;
public c() { } }
public class d extends Thread { private a b;
public d(a aVar) { this.b = aVar; }
public void run() { try { this.b.a(); } catch (Exception e) { e.printStackTrace(); } } }
/* renamed from: com.dji.video.codec.e$e reason: collision with other inner class name */ public class C0001e extends Thread { private b b;
public C0001e(b bVar) { this.b = bVar; }
public void run() { try { this.b.a(); } catch (Exception e) { e.printStackTrace(); } } }
public e() { this.b = null; this.c = null; this.l = 1280; this.m = 720; this.n = this.l; this.o = this.m; this.p = this.l; this.q = this.m; this.r = 0; this.s = 0; this.t = 0; this.u = 0; this.v = 0; this.w = 0; this.x = 0; this.y = 0; this.z = "video/avc"; this.A = 6000000; this.B = 6000000; this.C = 25; this.D = 25; this.E = -1; this.I = false; this.J = false; this.O = 0; this.P = false; this.X = false; this.b = e(); this.c = f(); }
static /* synthetic */ int J(e eVar) { int i2 = eVar.O; eVar.O = i2 + 1; return i2; }
static /* synthetic */ int L(e eVar) { int i2 = eVar.T; eVar.T = i2 + 1; return i2; }
/* access modifiers changed from: private */ public int a(MediaExtractor mediaExtractor) { return 0; }
/* access modifiers changed from: private */ public void a(byte[] bArr, byte[] bArr2, int i2, int i3, int i4, int i5) { }
private static boolean a(int i2) { if (!(i2 == 39 || i2 == 2130706688)) { switch (i2) { case 19: case 20: case 21: break; default: return false; } } return true; }
/* access modifiers changed from: private */ public static int b(MediaCodecInfo mediaCodecInfo, String str) { MediaCodecInfo.CodecCapabilities capabilitiesForType = mediaCodecInfo.getCapabilitiesForType(str); for (int i2 = 0; i2 < capabilitiesForType.colorFormats.length; i2++) { int i3 = capabilitiesForType.colorFormats[i2]; if (a(i3)) { return i3; } } Assert.fail("找不到适合的颜色格式 " + mediaCodecInfo.getName() + " / " + str); return 0; }
/* access modifiers changed from: private */ public static MediaCodecInfo b(String str) { String[] supportedTypes; int codecCount = MediaCodecList.getCodecCount(); for (int i2 = 0; i2 < codecCount; i2++) { MediaCodecInfo codecInfoAt = MediaCodecList.getCodecInfoAt(i2); if (codecInfoAt.isEncoder()) { for (String str2 : codecInfoAt.getSupportedTypes()) { if (str2.equalsIgnoreCase(str)) { return codecInfoAt; } } continue; } } return null; }
private static boolean b(int i2) { if (!(i2 == 39 || i2 == 2130706688)) { switch (i2) { case 19: case 20: return false; case 21: break; default: throw new RuntimeException("unknown format " + i2); } } return true; }
/* access modifiers changed from: private */ public void c(String str) { }
private void d() throws IOException { }
private String e() { return Build.MODEL; }
private String f() { return Build.VERSION.RELEASE; }
static /* synthetic */ int x(e eVar) { int i2 = eVar.M; eVar.M = i2 + 1; return i2; }
public void a() { }
public void a(long j2, long j3, int i2) { }
public void a(long j2, long j3, String str, String str2, String str3, int i2) { }
public void a(b bVar) { this.Y = bVar; }
public void b() { }
public void c() { }}

这段代码,emmm,啥也看不出出来了,只能猜了

https://www.android-doc.com/reference/android/media/MediaCodecInfo.CodecCapabilities.html
public static int b(MediaCodecInfo mediaCodecInfo, String str) { MediaCodecInfo.CodecCapabilities capabilitiesForType = mediaCodecInfo.getCapabilitiesForType(str); for (int i2 = 0; i2 < capabilitiesForType.colorFormats.length; i2++) { int i3 = capabilitiesForType.colorFormats[i2]; if (a(i3)) { return i3; } } Assert.fail("找不到适合的颜色格式 " + mediaCodecInfo.getName() + " / " + str); return 0; }

看这个函数,传入一个编码函数,和一个strings

然后就是一个遍历在匹配一个什么东西?应该是颜色的格式

package com.dji.video.codec;
import android.graphics.BitmapFactory;
public class ImageDecoder { private int a; private int b;
public static int[] get_image_paras(String str) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(str, options); return new int[]{options.outWidth, options.outHeight, 0, 0}; }
public int get_height() { return this.b; }
public int[] get_image_data(String str) { return null; }
public void get_image_para(String str) { }
public int get_width() { return this.a; }}

这个函数简单,见名知其义

package com.dji.video.codec;
import java.util.HashMap;import wseemann.media.FFmpegMediaMetadataRetriever;
public class VideoDescription { private static final String a = "VideoDescription"; private String b; private HashMap<String, String> c;
private void a(FFmpegMediaMetadataRetriever.a aVar, String str) { }
private native void nativeGetDescription(String str, HashMap<String, String> hashMap);
public void a(String str) { }
public String b(String str) { return null; }}

这个函数是读取一个视频的info


就先到这里~下期再见

(0)

相关推荐

  • java学习——92.简单记事本

    上一篇演示了"记事本"的大概功能. 本篇贴的是其代码. 本记事本有三个类: Start是main方法所在的类. Jsb是主类. GuanYu是关于窗口的类. 本处帖的是第一个类: ...

  • java学习——87.菜单

    日常所用到的每一个软件,几乎都会用到菜单. 菜单即打开软件顶上的那一排类似导航的按钮,但它又不是按钮.或者是右键时的快捷菜单,都是菜单. 本篇即介绍菜单组件. 菜单有两种使用方式:窗口菜单和快捷菜单. ...

  • 图解Java设计模式之备忘录模式

    游戏角色状态恢复问题 传统方案解决游戏角色恢复 传统的方式的问题分析 备忘录模式基本介绍 备忘录模式原理类图 游戏角色恢复状态实例 备忘录模式的注意事项和细节 游戏角色状态恢复问题 游戏角色有攻击力和 ...

  • Dji Mimo APP逆向.3

    对jar8的分析 先看结构 内部有对版本号码的判断,且打印log Android x应该是对实现的包 和注解 什么是注解(Annotation)?注解是放在Java源码的类.方法.字段.参数前的一种特 ...

  • Dji Mimo APP逆向.2

    Dji Mimo APP逆向.1(pocket 2直播模式+物体追踪)先接上~ 我又来了~继续翻阅代码     A("light_upload_release_click"),  ...

  • 大疆Dji pocket 一代研究(Dji Mimo)

    我前些日子入了一台云台相机,小巧的机身,强大的机身,反正就是喜欢的不行,作为一个半吊子程序员当然是想写个程序来控制它了.但是逛遍全网,就发现一个写2代HDMI连接的.和我有啥关系呢~~~ 哈哈哈,多花 ...

  • PHP直播APP系统源码,直播程序架构的基本知识

    当你想要开发一款直播系统时,你可能会选择找开发商,也可能想自己组建团队开发,但是无论你选择哪种方式,首先你都要考虑一个问题,那就是选择哪种语音进行直播系统源码的开发,而当你去参考其他平台的开发经验时, ...

  • 直播APP源代码,其他行业的直播APP表现如何

    直播做为新型的互动方式,它是社交的代表.是娱乐的代表,直播APP源代码也成为了一种新型的内容生产方式,直播平台是内容聚合的场所,随着直播越来越火热,它涉及的行业也越来越多,不仅仅是在娱乐行业内,其他行 ...

  • APP逆向案例---xxapp

    步骤一 抓个包 其中m_d,m_e为加密参数 步骤二(已经看了是360加固我们脱壳一下) # Author: hluwa <hluwa888@gmail.com># HomePage: h ...

  • 在线教育直播源码,APP+PC+后台,教育直播该怎么做?

    在线教育的独立设施数和用户活跃度上升,设备单机日使用时长超过100分钟,环比增长12.1%.在线教育直播源码的学习教育软件在人群中的渗透率进一步提升.很多的线下教培机构看准机会,纷纷入局在线教育市场, ...

  • 直播APP怎么开发制作,直播APP制作开发的流程

    虽然开发一个直播app并不是很难的事情,基本上会编程程序员就能开发出来.但是支持几个人同时直播和让上百万人一起直播却是两回事. 很多互联网创业项目会标配PC.Android.iOS三大平台,每个平台要 ...

  • 功能更新 | 小程序增加商城,打通视频号!商家APP、小班课、直播等功能优化!

    导读 创客匠人6月份功能升级来啦~ 本次功能迭代将于6月18日正式升级. 这一次的功能更新主要针对商家APP.小班课.直播.店铺装修.服务商.优惠券.商城等功能,进行升级迭代. 下面就来看看本次创客匠 ...