Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code not being encrypted #28

Open
dooleyb1 opened this issue Mar 23, 2020 · 21 comments
Open

Code not being encrypted #28

dooleyb1 opened this issue Mar 23, 2020 · 21 comments

Comments

@dooleyb1
Copy link

I have spent a good while playing around with multiple options and examples and can't seem to get it to work. My setup is the following:

"metro-react-native-babel-preset": "0.56.0",
"metro-react-native-babel-transformer": "^0.59.0",
 "react-native-obfuscating-transformer": "^1.0.0",
"react-native": "^0.61.0",

metro.config.js

/**
 * Metro configuration for React Native
 * https://github.com/facebook/react-native
 *
 * @format
 */

module.exports = {
  transformer: {
    babelTransformerPath: require.resolve("./transformer"),
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: false,
      },
    }),
  },
};

transformer.js

const obfuscatingTransformer = require("react-native-obfuscating-transformer")

const filter = filename => { 
  return filename.startsWith("src");
};

module.exports = obfuscatingTransformer({
// this configuration is based on https://github.com/javascript-obfuscator/javascript-obfuscator
  obfuscatorOptions:{
    compact: true,
    controlFlowFlattening: false,
    deadCodeInjection: false,
    debugProtection: false,
    debugProtectionInterval: false,
    disableConsoleOutput: true,
    identifierNamesGenerator: 'hexadecimal',
    log: false,
    renameGlobals: false,
    rotateStringArray: true,
    selfDefending: true,
    shuffleStringArray: true,
    splitStrings: false,
    stringArray: true,
    stringArrayEncoding: false,
    stringArrayThreshold: 0.75,
    unicodeEscapeSequence: false
  },
  upstreamTransformer: require('metro-react-native-babel-transformer'),
  emitObfuscatedFiles: false,
  enableInDevelopment: true,
  filter: filter,
  trace: true
})

The command I am using to build the output js bundle for testing is the following:

npx react-native bundle --entry-file=index.js --bundle-output='./bundle.js' --dev=false --platform='ios' --assets-dest='./ios' --reset-cache

I can see the output from stdout of the transformer logging which files are being obfuscated, however when I look at the entire bundle and even the sub obfuscated files, the variable names and function calls are not encrypted.

Below is an example of a before and after obfuscation:

Before (screens.js):

import { Navigation } from 'react-native-navigation';
import { Provider } from 'react-redux';

import firebase from 'react-native-firebase';
const crashlytics = firebase.crashlytics();

import configureStore from 'app/store';

// Initialise global store
export const store = configureStore()

export function registerScreens() {

  crashlytics.enableCrashlyticsCollection();
  crashlytics.log('[utils][screens] - Registering screens...');

  // Register screens with redux stores
  Navigation.registerComponentWithRedux('Initialising', () => require('screens/Initialising').default, Provider, store);
  Navigation.registerComponentWithRedux('Auth', () => require('screens/Auth').default, Provider, store);
  Navigation.registerComponentWithRedux('VerifyPhoneNumber', () => require('screens/VerifyPhoneNumber').default, Provider, store);
  Navigation.registerComponentWithRedux('SignIn', () => require('screens/SignIn').default, Provider, store);

  // Profile Stack
  Navigation.registerComponentWithRedux('Profile', () => require('screens/Profile').default, Provider, store);
  Navigation.registerComponentWithRedux('QRScanner', () => require('screens/Profile/QRScanner').default, Provider, store);

  // Register Stack
  Navigation.registerComponentWithRedux('InitialRegister', () => require('screens/Register/InitialRegister').default, Provider, store);
  Navigation.registerComponentWithRedux('RegisterDetails', () => require('screens/Register/RegisterDetails').default, Provider, store);

  // Rewards Stack
  Navigation.registerComponentWithRedux('Rewards', () => require('screens/Rewards').default, Provider, store);
  Navigation.registerComponentWithRedux('RewardBack', () => require('screens/Rewards/RewardBack').default, Provider, store);
  Navigation.registerComponentWithRedux('RewardRedeemed', () => require('screens/Rewards/RewardRedeemed').default, Provider, store);

  // Home stack
  Navigation.registerComponentWithRedux('Home', () => require('screens/Home').default, Provider, store);

  // Marketplace stack
  Navigation.registerComponentWithRedux('MarketplaceBack', () => require('screens/Rewards/MarketplaceBack').default, Provider, store);

  // Bundles
  Navigation.registerComponentWithRedux('PreBundle', () => require('screens/Home/PreBundle').default, Provider, store);
  Navigation.registerComponentWithRedux('BundleQuestion', () => require('screens/Home/BundleQuestion').default, Provider, store);
  Navigation.registerComponentWithRedux('BundleComplete', () => require('screens/Home/BundleComplete').default, Provider, store);

  // Help Screens
  Navigation.registerComponentWithRedux('HomeHelp', () => require('screens/Help/HomeHelp').default, Provider, store);
  Navigation.registerComponentWithRedux('RewardsHelp', () => require('screens/Help/RewardsHelp').default, Provider, store);

  // Modals
  Navigation.registerComponentWithRedux('VersionUpdateModal', () => require('misc/Modals/VersionUpdateModal').default, Provider, store);
  Navigation.registerComponentWithRedux('PolicyUpdateModal', () => require('misc/Modals/PolicyUpdateModal').default, Provider, store);
}

After (screens.obfuscated.js):

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.registerScreens = registerScreens;exports.store = void 0;var _reactNativeNavigation = require("react-native-navigation");
var _reactRedux = require("react-redux");

var _reactNativeFirebase = _interopRequireDefault(require("react-native-firebase"));


var _store = _interopRequireDefault(require("../../store"));var crashlytics = _reactNativeFirebase.default.crashlytics();

// Initialise global store
var store = (0, _store.default)();exports.store = store;

function registerScreens() {

  crashlytics.enableCrashlyticsCollection();
  crashlytics.log('[utils][screens] - Registering screens...');

  // Register screens with redux stores
  _reactNativeNavigation.Navigation.registerComponentWithRedux('Initialising', function () {return require("../components/screens/Initialising").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('Auth', function () {return require("../components/screens/Auth").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('VerifyPhoneNumber', function () {return require("../components/screens/VerifyPhoneNumber").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('SignIn', function () {return require("../components/screens/SignIn").default;}, _reactRedux.Provider, store);

  // Profile Stack
  _reactNativeNavigation.Navigation.registerComponentWithRedux('Profile', function () {return require("../components/screens/Profile").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('QRScanner', function () {return require("../components/screens/Profile/QRScanner").default;}, _reactRedux.Provider, store);

  // Register Stack
  _reactNativeNavigation.Navigation.registerComponentWithRedux('InitialRegister', function () {return require("../components/screens/Register/InitialRegister").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('RegisterDetails', function () {return require("../components/screens/Register/RegisterDetails").default;}, _reactRedux.Provider, store);

  // Rewards Stack
  _reactNativeNavigation.Navigation.registerComponentWithRedux('Rewards', function () {return require("../components/screens/Rewards").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('RewardBack', function () {return require("../components/screens/Rewards/RewardBack").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('RewardRedeemed', function () {return require("../components/screens/Rewards/RewardRedeemed").default;}, _reactRedux.Provider, store);

  // Home stack
  _reactNativeNavigation.Navigation.registerComponentWithRedux('Home', function () {return require("../components/screens/Home").default;}, _reactRedux.Provider, store);

  // Marketplace stack
  _reactNativeNavigation.Navigation.registerComponentWithRedux('MarketplaceBack', function () {return require("../components/screens/Rewards/MarketplaceBack").default;}, _reactRedux.Provider, store);

  // Bundles
  _reactNativeNavigation.Navigation.registerComponentWithRedux('PreBundle', function () {return require("../components/screens/Home/PreBundle").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('BundleQuestion', function () {return require("../components/screens/Home/BundleQuestion").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('BundleComplete', function () {return require("../components/screens/Home/BundleComplete").default;}, _reactRedux.Provider, store);

  // Help Screens
  _reactNativeNavigation.Navigation.registerComponentWithRedux('HomeHelp', function () {return require("../components/screens/Help/HomeHelp").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('RewardsHelp', function () {return require("../components/screens/Help/RewardsHelp").default;}, _reactRedux.Provider, store);

  // Modals
  _reactNativeNavigation.Navigation.registerComponentWithRedux('VersionUpdateModal', function () {return require("../components/misc/Modals/VersionUpdateModal").default;}, _reactRedux.Provider, store);
  _reactNativeNavigation.Navigation.registerComponentWithRedux('PolicyUpdateModal', function () {return require("../components/misc/Modals/PolicyUpdateModal").default;}, _reactRedux.Provider, store);
}
@AustinZuniga
Copy link

I solved this by modifying obfuscatingTransformer.js in node_modules\react-native-obfuscating-transformer\dist\

change

fs.writeFileSync(path.join(emitDir, filename), code);

to

fs.writeFileSync(path.join(emitDir, filename), obfuscateCode_1.obfuscateCode(code, obfuscatorOptions));

it seems the author forgot to modify this one.

@dooleyb1
Copy link
Author

I solved this by modifying obfuscatingTransformer.js in node_modules\react-native-obfuscating-transformer\dist\

change

fs.writeFileSync(path.join(emitDir, filename), code);

to

fs.writeFileSync(path.join(emitDir, filename), obfuscateCode_1.obfuscateCode(code, obfuscatorOptions));

it seems the author forgot to modify this one.

@AustinZuniga thanks man that worked perfectly for the individual obfuscated files, however it still seems to have no effect on the overall bundle.js file. Any idea?

@AustinZuniga
Copy link

I solved this by modifying obfuscatingTransformer.js in node_modules\react-native-obfuscating-transformer\dist
change

fs.writeFileSync(path.join(emitDir, filename), code);

to

fs.writeFileSync(path.join(emitDir, filename), obfuscateCode_1.obfuscateCode(code, obfuscatorOptions));

it seems the author forgot to modify this one.

@AustinZuniga thanks man that worked perfectly for the individual obfuscated files, however it still seems to have no effect on the overall bundle.js file. Any idea?

I noticed that one too. Try comparing bundle.js with and without using react-native-obfuscating-transformer. Use a JS code beautifier and diff file tool to see the difference. It seems react-native-obfuscating-transformer is working by obfuscating the code, but the identifier names not turning into hexadecimal or mangled algorithm. Maybe it has something to do with metro transformer

@dooleyb1
Copy link
Author

I solved this by modifying obfuscatingTransformer.js in node_modules\react-native-obfuscating-transformer\dist
change

fs.writeFileSync(path.join(emitDir, filename), code);

to

fs.writeFileSync(path.join(emitDir, filename), obfuscateCode_1.obfuscateCode(code, obfuscatorOptions));

it seems the author forgot to modify this one.

@AustinZuniga thanks man that worked perfectly for the individual obfuscated files, however it still seems to have no effect on the overall bundle.js file. Any idea?

I noticed that one too. Try comparing bundle.js with and without using react-native-obfuscating-transformer. Use a JS code beautifier and diff file tool to see the difference. It seems react-native-obfuscating-transformer is working by obfuscating the code, but the identifier names not turning into hexadecimal or mangled algorithm. Maybe it has something to do with metro transformer

Yeah I can see from looking at the bundle.js that the code has definitely been changed and obfuscated a bit. Would just love for the identifier names to turn into the hexadecimal hash. Will leave this issue open and see if anyone can help. Thanks 👍

@filippoitaliano
Copy link

Hi! I tried several set of options with the same result: no obfuscation. I can see some differences between the original bundle and the obfuscated one but essentially nothing about stringsArray or selfDefence for instance. I can see the logs during bundling phase and I get the "obfuscated" files saved alongside the original ones so I assume the module is correctly integrated in metro config. The last configuration I experimented with is identical to the one shown by @dooleyb1 and the result is the same.

@adevfromhere
Copy link

Hi! I tried several set of options with the same result: no obfuscation. I can see some differences between the original bundle and the obfuscated one but essentially nothing about stringsArray or selfDefence for instance. I can see the logs during bundling phase and I get the "obfuscated" files saved alongside the original ones so I assume the module is correctly integrated in metro config. The last configuration I experimented with is identical to the one shown by @dooleyb1 and the result is the same.

Yep, seeing the same...

@adevfromhere
Copy link

adevfromhere commented Apr 2, 2020

I believe I found the root cause as to why variable / property and function names are not being obfuscated.
Metrobundler transforms each javascript file independantly, and in obfuscateCode.js only Obfuscator.obfuscate is called, which leads me to believe that as each file is transformed, they don't have ref to all the objects to fully obfuscate.

The docs for javascript-obfuscator/javascript-obfuscator state that Obfuscator.obfuscateMultiple should be called.

@dooleyb1
Copy link
Author

dooleyb1 commented Apr 2, 2020

I believe I found the root cause as to why variable / property and function names are not being obfuscated.
Metrobundler transforms each javascript file independantly, and in obfuscateCode.js only Obfuscator.obfuscate is called, which leads me to believe that as each file is transformed, they don't have ref to all the objects to fully obfuscate.

The docs for javascript-obfuscator/javascript-obfuscator state that Obfuscator.obfuscateMultiple should be called.

Have you tried changing the Obfuscator.obfuscate to Obfuscator.obfuscateMultiple method and seeing if it works?

@adevfromhere
Copy link

Not yet, it will take some time to figure out how to map all my flow objects to obfuscateMultiple.

@adevfromhere
Copy link

I won't have time to look into this until late next week (and I can't promise I will have time.)

In a nutshell I believe that obfuscateCode.js should be calling Obfuscator.obfuscateMultiple instead of Obfuscator.obfuscate.

Another thing to take into consideration is that some RN projects use Flow vs TypeScript. I'd only look into creating a patch that works with Flow, if applicable.

@filippoitaliano
Copy link

I still have flow types in a lot of legacy modules for instance. I'll migrate but progressively during functional refactoring not because I have typing issues.

@dooleyb1
Copy link
Author

@filippoitaliano @TraneKJ @AustinZuniga Hey guys, have any of yous managed to get anywhere? Still no luck on my side.

@filippoitaliano
Copy link

Nowhere, I'm sorry! I abandoned obfuscation for now. This lib seems to be one of the most comprehensive out there but I didn't manage to make it work.

@adevfromhere
Copy link

No progress, my team had me do a POC with Jscrambler first, which I've done, and it works great, but for a heafty price-tag.
The company I work for is now weighing the options of paying Jscrambler the annual subscription fee to handle obfuscation / anti-tampering, or giving me a work-item to fix what's broken in this open source library.
I wont know for another 2 week if they choose the latter, if they do I will let this thread know.

@barak109
Copy link

@dooleyb1 @TraneKJ @filippoitaliano @AustinZuniga Any advise guys? doesn't work for me either

@dooleyb1
Copy link
Author

@dooleyb1 @TraneKJ @filippoitaliano @AustinZuniga Any advise guys? doesn't work for me either

None yet unfortunately

@Quantum-35
Copy link

@adevfromhere What option did you go with?

@whoami-shubham
Copy link

try this plugin https://www.npmjs.com/package/obfuscator-io-metro-plugin

@Karthi27p
Copy link

try this plugin https://www.npmjs.com/package/obfuscator-io-metro-plugin

Can we use the source map generated by the obfuscator-io-metro-plugin to de obfuscate and symbolicate the line of crash in react native

@hannigand
Copy link

hannigand commented Feb 24, 2021

@dooleyb1 did you manage to resolve this? If not, did you use an alternative solution?

My files don't appear to be obfuscated at all.

Original file:

const App: React.FC = () => {
  const myApiKey = 'foo';
  console.log(myApiKey);

Obfuscated file:

var App = function App() {
  var myApiKey = 'foo';
  console.log(myApiKey);

With the following packages

"metro-react-native-babel-preset": "^0.59.0",
"react-native-typescript-transformer": "^1.2.13",
"react-native-obfuscating-transformer": "^1.0.0",
"react-native": "0.63.3",

@dooleyb1
Copy link
Author

@dooleyb1 did you manage to resolve this? If not, did you use an alternative solution?

My files don't appear to be obfuscated at all.

Original file:

const App: React.FC = () => {
  const myApiKey = 'foo';
  console.log(myApiKey);

Obfuscated file:

var App = function App() {
  var myApiKey = 'foo';
  console.log(myApiKey);

With the following packages

"metro-react-native-babel-preset": "^0.59.0",
"react-native-typescript-transformer": "^1.2.13",
"react-native-obfuscating-transformer": "^1.0.0",
"react-native": "0.63.3",

@hannigand No unfortunately I gave up attempting to implement obfuscation on my files and have not re-attempted since.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants