The TikTok Spyware Conspiracy

by August GL (live from the hacker den) (augustgl@protonmail.ch)

Last year, towards the end of 2020, I came across a couple of articles claiming that TikTok, a large social media platform, is spyware.

TikTok rose from the ashes when Musical.ly died in like 2018 or something, I don't know.  It's essentially "funny videos/dancing ."

TikTok is currently owned by a company based in China known as "Byte Dance."

Personally, I don't like TikTok, but if you use it, fine.  I myself will never.  But not because I don't like it.  I'll never use it because of the things I found when I reverse engineered the app.

I downloaded an APK for TikTok.  An APK is essentially a ZIP file, but it has all the necessary components inside to install an Android application.  I unzipped it with unzip.  Android applications are written in Java.  I hate Java because it's one of those languages that is reverse engineered ridiculously easy, like C# (Microsoft Java).  But before the Java code can be run on the phone, it has to be compiled into a DEX file.  A DEX is a Dalvik Executable, which is what the Java code gets turned into when it's finally ready to be ran on the phone.

So I have a DEX, and not a JAR, the type of file that my Java decompiler accepts.  Well, looks like the article is over guys!  Thanks for reading.

Just kidding.  I ran a tool called dex2jar that converted it to a JAR file.  I placed that in the Java decompiler, and I was looking at the decompiled Java source code.  And it was huge.  I sifted through it for a couple of hours and found the main part.  And then I started reading.

Now, I'm not saying 100 percent for sure that this code is malicious, but it's very sketchy, and extremely personal, like the crackhead you see outside 7-Eleven at 1 a.m. who comes half-an-inch from your face to start asking you questions about your life.  Here are some amazing code snippets I found.

This is from a file called LoadAddressTask.java:
  private void loadDistrictFromCity(JSONObject paramJSONObject) throws JSONException {
    if (paramJSONObject == null)
      return; 
    ArrayList<AddressInfo> arrayList = new ArrayList();
    JSONArray jSONArray = paramJSONObject.getJSONArray("regionEntitys");
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(paramJSONObject.getString("region"));
    stringBuilder.append(paramJSONObject.getString("code"));
    stringBuilder.append("city");
    String str = stringBuilder.toString();
    for (int i = 0; i < jSONArray.length(); i++)
      arrayList.add(new AddressInfo(jSONArray.getJSONObject(i).getString("region"), jSONArray.getJSONObject(i).getString("code"), "district")); 
    if (arrayList.size() <= 0) {
      arrayList.add(new AddressInfo(this.DEFAULT_DISTRICT_CHINA, "", "district"));
      mCache.put(str, arrayList);
      mDepthCache.put(str, Integer.valueOf(2));
      return;
    } 
    mCache.put(str, arrayList);
    mDepthCache.put(str, Integer.valueOf(2));
  }

  private List<AddressInfo> loadProvince(JSONArray paramJSONArray) throws JSONException {
    ArrayList<AddressInfo> arrayList = new ArrayList();
    for (int i = 0; i < paramJSONArray.length(); i++) {
      JSONObject jSONObject = paramJSONArray.getJSONObject(i);
      String str1 = jSONObject.getString("region");
      String str2 = jSONObject.getString("code");
      loadCityFromProvince(jSONObject);
      if (!arrayList.contains(str1))
        arrayList.add(new AddressInfo(str1, str2, "province")); 
    } 
    mCache.put("province", arrayList);
    mDepthCache.put("province", Integer.valueOf(0));
    return arrayList;
  }

Seems legit.  To be fair, this could be used legitimately, but I don't like it.  Moving on to another snippet from a file called AppbrandMapActivity.java:

  private void requestPermission() {
    HashSet<String> hashSet = new HashSet();
    hashSet.add("android.permission.ACCESS_COARSE_LOCATION");
    hashSet.add("android.permission.ACCESS_FINE_LOCATION");
    PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult((Activity)this, hashSet, new PermissionsResultAction() {
          public void onDenied(String param1String) {
            AppbrandMapActivity.this.moveCamera();
            AppbrandMapActivity.this.initEndPoint();
          }
          
          public void onGranted() {
            try {
              AppbrandMapActivity.this.moveCamera();
              AppbrandMapActivity.this.initEndPoint();
              return;
            } catch (Exception exception) {
              AppBrandLogger.e("tma_AppbrandMapActivity", new Object[] { "", exception });
              return;
            } 
          }
        });
  }

I am no Android programmer, and I definitely cannot develop in Java, but I can see what's happening here.  The two important lines are these:

hashSet.add("android.permission.ACCESS_COARSE_LOCATION");
hashSet.add("android.permission.ACCESS_FINE_LOCATION");

I went on the Android developer site and found that this is what ACCESS_FINE_LOCATION requests: "Allows an app to access precise location."

Why does TikTok need my precise location?  It shouldn't.  The last code snippet we'll look at is this, from a file called TMALocation.java:

  public static TMALocation fromJson(JSONObject paramJSONObject) throws JSONException {
    if (paramJSONObject == null)
      return null; 
    TMALocation tMALocation = new TMALocation(paramJSONObject.optString("provider"));
    tMALocation.setLatitude(paramJSONObject.optDouble("latitude"));
    tMALocation.setLongitude(paramJSONObject.optDouble("longitude"));
    tMALocation.setTime(paramJSONObject.optLong("loc_time"));
    tMALocation.setSpeed((float)paramJSONObject.optDouble("speed", 0.0D));
    tMALocation.setAccuracy((float)paramJSONObject.optDouble("accuracy"));
    tMALocation.setAltitude(paramJSONObject.optDouble("altitude"));
    tMALocation.setStatusCode(paramJSONObject.optInt("statusCode"));
    tMALocation.setRawImplStatusCode(paramJSONObject.optInt("rawImplStatusCode"));
    tMALocation.setAddress(paramJSONObject.optString("address"));
    tMALocation.setCountry(paramJSONObject.optString("country"));
    tMALocation.setProvince(paramJSONObject.optString("province"));
    tMALocation.setCity(paramJSONObject.optString("city"));
    tMALocation.setDistrict(paramJSONObject.optString("district"));
    tMALocation.setLocType(paramJSONObject.optInt("loctype"));
    if (Build.VERSION.SDK_INT >= 26)
      tMALocation.setVerticalAccuracyMeters(0.0F); 
    return tMALocation;
  }

// code code code it's too long to put it all

  public JSONObject toJson() {
    JSONObject jSONObject = new JSONObject();
    try {
      jSONObject.putOpt("provider", getProvider());
      jSONObject.putOpt("latitude", Double.valueOf(getLatitude()));
      jSONObject.putOpt("longitude", Double.valueOf(getLongitude()));
      jSONObject.putOpt("loc_time", Long.valueOf(getTime()));
      jSONObject.putOpt("speed", Float.valueOf(getSpeed()));
      jSONObject.putOpt("accuracy", Float.valueOf(getAccuracy()));
      jSONObject.putOpt("altitude", Double.valueOf(getAltitude()));
      jSONObject.putOpt("statusCode", Integer.valueOf(getStatusCode()));
      jSONObject.putOpt("rawImplStatusCode", Integer.valueOf(getRawImplStatusCode()));
      jSONObject.putOpt("address", getAddress());
      jSONObject.putOpt("country", getCountry());
      jSONObject.putOpt("province", getProvince());
      jSONObject.putOpt("city", getCity());
      jSONObject.putOpt("district", getDistrict());
      jSONObject.putOpt("loctype", Integer.valueOf(getLocType()));
      float f = 0.0F;
      if (Build.VERSION.SDK_INT >= 26)
        f = getVerticalAccuracyMeters(); 
      jSONObject.put("verticalAccuracy", f);
      return jSONObject;
    } catch (JSONException jSONException) {
      AppBrandLogger.eWithThrowable("TMALocation", "tojson", (Throwable)jSONException);
      return jSONObject;
    } 
  }

Yeah guys, this seems like a legit social media platform to me.  Why does it need that much information!?  Why does it need my f*cking altitude?

Keep in mind, all of this code could be used legitimately.  But looking at TikTok as a platform, I don't see why they need my latitude and longitude.

So, after I had reverse engineered TikTok, I sat back and thought for a minute.  And then I released it on GitHub.  It blew up.  I got 65 plus stars in two days.  TikTok found out, and they were not happy about it.  The GitHub repo was taken down, and I received a DMCA takedown notice.  The DMCA notice is kinda long, so here's the important part:

GitHub:  Please provide a detailed description of the original copyrighted work that has allegedly been infringed.  If possible, include a URL to where it is posted online.

TikTok Legal Jackass:  The original copyrighted work is source code for the TikTokAndroid app.  Github user augustgl appears to claim to have reverse engineered the app.  He posted the code to the following GitHub repository: https://github.com/augustgl/tiktok_source

"appears to claim to have reverse engineered the app"

"claim"

I don't "claim to have reverse engineered the app," I reverse engineered the app.

The process for reverse engineering an Android application summarized is this:

  1. Obtain a copy of the APK for the app in question.
  2. Unzip with the unzip GNU/Linux utility like you would a regular ZIP file.
  3. Run dex2jar on the DEX file in the unzipped directory.  You now have a JAR file.
  4. Put the JAR in any Java decompiler.
  5. And you're looking at source code!

Thanks for reading.  Good luck in this foul year of our lord, 2021.

Return to $2600 Index