Java 在混淆代码中隐藏字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4427238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 17:19:57  来源:igfitidea点击:

Hiding strings in Obfuscated code

javaandroidproguard

提问by jax

I just Obfuscated my Android code using proguard and then decompiled it. There are a number of strings I would really like to hide from prying eyes. When I decompiled my code the strings were there for everyone to see...and change. One of the strings is a URL to my licensing server and they could in effect change the url to point to a fake server (as I will be releasing the server code to the public). What is the best way of hiding this sort of information?

我只是使用 proguard 混淆了我的 Android 代码,然后对其进行了反编译。有很多字符串我真的很想隐藏起来以免被窥探。当我反编译我的代码时,每个人都可以看到字符串……并更改。其中一个字符串是我的许可服务器的 URL,它们实际上可以将 URL 更改为指向假服务器(因为我将向公众发布服务器代码)。隐藏此类信息的最佳方法是什么?

Also, I noticed that the R class strings are all random numbers but I can't find the R class in the decompiled code. Where is it?

另外,我注意到 R 类字符串都是随机数,但在反编译代码中找不到 R 类。它在哪里?

Foe exampleI see: new SimpleCursorAdapter(localActivity, 2130903058, localCursor, arrayOfString, arrayOfInt);

我看到的敌人示例new SimpleCursorAdapter(localActivity, 2130903058, localCursor, arrayOfString, arrayOfInt);

2130903058 is a layout file but what is it referencing? The number means nothing unless it is pointing to some sort of address.

2130903058 是一个布局文件,但它引用的是什么?该数字没有任何意义,除非它指向某种地址。

采纳答案by Mark Hibberd

Assuming you are happy with obscure rather than secure, there a number of mechanisms you could use, but obfuscaters like proguard are not going to be able to help you.

假设您对模糊而不是安全感到满意,您可以使用许多机制,但是像 proguard 这样的混淆器将无法帮助您。

To achieve this you will need to do encoding or encryption of the string yourself, the approach you use depends on what you are trying to defend against, if it you are just trying to hide from obvious inspection, than encoding may be sufficient (see android.util.Base64, http://developer.android.com/reference/android/util/Base64.html). Note that encoding is in NO WAY SECURE and all it will to is remove the obvious reference to your site.

要实现这一点,您需要自己对字符串进行编码或加密,您使用的方法取决于您要防御的内容,如果您只是想躲避明显的检查,那么编码可能就足够了(参见 android .util.Base64,http://developer.android.com/reference/android/util/Base64.html)。请注意,编码是绝对不安全的,它只会删除对您网站的明显引用。

If you are trying to defend against something more, then you could move to actually encrypting the string, to do this you would use a symmetric cipher like AES via javax.crypto.Cipher, http://www.androidsnippets.org/snippets/39/index.htmlprovides a decent usage example. Again this is more annoying then secure to would be hackers, as you will need to store the key somewhere in your jar thus negating any cryptographic security.

如果你想防御更多的东西,那么你可以转向实际加密字符串,为此你可以通过 javax.crypto.Cipher 使用对称密码,如 AES,http://www.androidsnippets.org/snippets/ 39/index.html提供了一个不错的使用示例。同样,这对黑客来说比安全更烦人,因为您需要将密钥存储在 jar 中的某个位置,从而否定任何加密安全性。

To make this clearer, the basic steps would be:

为了更清楚地说明这一点,基本步骤是:

  1. Manually create an encrypt your string using a known key.
  2. Convert your code to use a decrypted version of this string, example:
  1. 使用已知密钥手动创建加密字符串。
  2. 转换您的代码以使用此字符串的解密版本,例如:

Before:

前:

public class Foo {
    private String mySecret = "http://example.com";

    ...
}

Becomes:

变成:

public class Foo {
    private String encrypted = "<manually created encrypted string>";
    private String key = "<key used for encryption";
    private String mySecret = MyDecryptUtil.decrypt(encrypted, key);

    ...
}

A (good) alternative to all of this is considering using a third party drm solution such as the licensing server google provides http://android-developers.blogspot.com/2010/07/licensing-service-for-android.html. This may be more secure than something you roll your self, but is subject to very similar limitations to what I described above.

所有这些的(好的)替代方案是考虑使用第三方 drm 解决方案,例如谷歌提供的许可服务器http://android-developers.blogspot.com/2010/07/licensing-service-for-android.html。这可能比你自己滚动的东西更安全,但受到与我上面描述的非常相似的限制。

回答by iuiz

You should google for "Just another Perl hacker". These are programms that print out a string with obfuscated code. There are also lots of examples in other languages then Perl on the net.

你应该谷歌搜索“只是另一个 Perl 黑客”。这些是打印出带有混淆代码的字符串的程序。还有很多其他语言的例子,然后是网络上的 Perl。

Wikipedia entry

维基百科词条

回答by Someone Somewhere

what I did was create a long list of static strings in my global utility class. Someplace within the long list of strings I put my passkey in multiple chunks.

我所做的是在我的全局实用程序类中创建一长串静态字符串。在长长的字符串列表中的某个地方,我将我的密码分成多个块。

with my code it's easy to see what the real passkeys are - but once the obfuscator gets to work all the statics will have name like A, B, C, etc. and it won't be easy to spot any more.

用我的代码很容易看出真正的密码是什么——但是一旦混淆器开始工作,所有的静态变量都会有像 A、B、C 等这样的名字,而且再也不容易发现了。

回答by w_g

I used ROT47. It's not very secure, but easy to use and implement, because it's a symetric encoder/decoder

我使用了 ROT47。它不是很安全,但易于使用和实现,因为它是一个对称编码器/解码器

回答by Ahmad Ronagh

You can use DexGuardto encrypt strings, probably more effectively than you could achieve manually, and without burdening the source code.

您可以使用DexGuard来加密字符串,这可能比手动实现更有效,而且不会增加源代码的负担。

回答by cibercitizen1

Hi all.

大家好。

  1. Let secretbe the text you want to hide

  2. Find the keyhash of your debug/release.keystore. Let k1be this key.

  1. 让我们secret成为你想要隐藏的文字

  2. 找到你的 debug/release.keystore 的 keyhash。让k1这把钥匙。

(use tools keytool+openssl: keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64 )

(使用的工具,在keytool + OpenSSL的:keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

  1. Use a tool (external to the android code) to encrypt secretwith k1

    encrypted = encode (secret, k1)

  1. 使用的工具(外部Android的代码)来加密secretk1

    encrypted = encode (secret, k1)

(For instance: https://jwt.io, for java: https://github.com/jwtk/jjwt).

(例如:https: //jwt.io,对于java:https: //github.com/jwtk/jjwt)。

  1. In your android java code write down encrypted. When you need the decoded version of encrypted(this is, the original secret) write
  1. 在你的 android java 代码中写下encrypted. 当您需要encrypted(这是原始secret)的解码版本时,请编写

original = decode(encrypted, get_my_keyhash_programmatically() )

original = decode(encrypted, get_my_keyhash_programmatically() )

That's all.This works because the original secretis not shown on java source code, neither the k1to decode it. And, if a hacker wants to print your decoded secret, he must change code and recompile, signing his .apk with his own keystore not yours, and thus not getting the right original secret. (The "only" point is whether k1can be figured out from your original .apk).

就这样。这是有效的,因为原始文件secret未显示在 java 源代码中,也未对其k1进行解码。而且,如果黑客想要打印您解码的秘密,他必须更改代码并重新编译,使用他自己的而不是您的密钥库签署他的 .apk,从而无法获得正确的原始 .apk secret。(“唯一”的一点是是否k1可以从您的原始 .apk 中找出来)。

Note: get_my_keyhash_programmatically():

注意:get_my_keyhash_programmatically():

try {
    PackageInfo info = getPackageManager().getPackageInfo(
            "el nombre de su paquete por ejemplo com.tarea.u8",
            PackageManager.GET_SIGNATURES);
    for (Signature signature : info.signatures) {
        MessageDigest md = MessageDigest.getInstance("SHA");
        md.update(signature.toByteArray());
        Log.d("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT));
    }
} catch (PackageManager.NameNotFoundException e) {

} catch (NoSuchAlgorithmException e) {

}

回答by SSpoke

Here is what I currently use it has hacks to support sprintf functions which spilled plain-text in compiled binary file. You could now use w_sprintf_s instead of sprintf, like so

这是我目前使用的东西,它具有支持 sprintf 函数的技巧,这些函数在已编译的二进制文件中溢出纯文本。您现在可以使用 w_sprintf_s 而不是 sprintf,就像这样

char test[256] = { 0 };
w_sprintf_s(test, 256, XorStr("test test :D %d %+d\n"), 1, 1337);

or use it like this to print stuff on screen for example

或者像这样使用它在屏幕上打印东西,例如

w_printf(XorStr("test I print this and can't see me inside .dll or .exe"));

works on variables, if you have a custom printf() you could use that as well..

适用于变量,如果你有一个自定义的 printf() 你也可以使用它..

char szGuid[255] = { 0 };
//generate serial code removed.
char finalSerial[512] = { 0 };
XorCompileTime::w_sprintf(finalSerial, XorStr("serial information=%s"), szGuid);
myprintf(XorStr("Your Hardware ID: %s\n"), szGuid);


May add support for wchar_t wide strings like arkan did.. but I have no use for them right now as I don't write anything in symbols / unicode.


可能会像 arkan 那样添加对 wchar_t 宽字符串的支持..但我现在没有用它们,因为我没有用符号/unicode 写任何东西。

Here is a file just rename the code below to a XorString.hfile and include it in your project simple as that

这是一个文件,只需将下面的代码重命名为XorString.h文件并将其包含在您的项目中,就这么简单

#pragma once
#include <string>
#include <array>
#include <cstdarg>

#define BEGIN_NAMESPACE( x ) namespace x {
#define END_NAMESPACE }

BEGIN_NAMESPACE(XorCompileTime)

constexpr auto time = __TIME__;
constexpr auto seed = static_cast< int >(time[7]) + static_cast< int >(time[6]) * 10 + static_cast< int >(time[4]) * 60 + static_cast< int >(time[3]) * 600 + static_cast< int >(time[1]) * 3600 + static_cast< int >(time[0]) * 36000;

// 1988, Stephen Park and Keith Miller
// "Random Number Generators: Good Ones Are Hard To Find", considered as "minimal standard"
// Park-Miller 31 bit pseudo-random number generator, implemented with G. Carta's optimisation:
// with 32-bit math and without division

template < int N >
struct RandomGenerator
{
private:
    static constexpr unsigned a = 16807; // 7^5
    static constexpr unsigned m = 2147483647; // 2^31 - 1

    static constexpr unsigned s = RandomGenerator< N - 1 >::value;
    static constexpr unsigned lo = a * (s & 0xFFFF); // Multiply lower 16 bits by 16807
    static constexpr unsigned hi = a * (s >> 16); // Multiply higher 16 bits by 16807
    static constexpr unsigned lo2 = lo + ((hi & 0x7FFF) << 16); // Combine lower 15 bits of hi with lo's upper bits
    static constexpr unsigned hi2 = hi >> 15; // Discard lower 15 bits of hi
    static constexpr unsigned lo3 = lo2 + hi;

public:
    static constexpr unsigned max = m;
    static constexpr unsigned value = lo3 > m ? lo3 - m : lo3;
};

template <>
struct RandomGenerator< 0 >
{
    static constexpr unsigned value = seed;
};

template < int N, int M >
struct RandomInt
{
    static constexpr auto value = RandomGenerator< N + 1 >::value % M;
};

template < int N >
struct RandomChar
{
    static const char value = static_cast< char >(1 + RandomInt< N, 0x7F - 1 >::value);
};

template < size_t N, int K >
struct XorString
{
private:
    const char _key;
    std::array< char, N + 1 > _encrypted;

    constexpr char enc(char c) const
    {
        return c ^ _key;
    }

    char dec(char c) const
    {
        return c ^ _key;
    }

public:
    template < size_t... Is >
    constexpr __forceinline XorString(const char* str, std::index_sequence< Is... >) : _key(RandomChar< K >::value), _encrypted{ enc(str[Is])... }
    {
    }

    __forceinline decltype(auto) decrypt(void)
    {
        for (size_t i = 0; i < N; ++i) {
            _encrypted[i] = dec(_encrypted[i]);
        }
        _encrypted[N] = '##代码##';
        return _encrypted.data();
    }
};

//--------------------------------------------------------------------------------
//-- Note: XorStr will __NOT__ work directly with functions like printf.
//         To work with them you need a wrapper function that takes a const char*
//         as parameter and passes it to printf and alike.
//
//         The Microsoft Compiler/Linker is not working correctly with variadic 
//         templates!
//  
//         Use the functions below or use std::cout (and similar)!
//--------------------------------------------------------------------------------

static auto w_printf = [](const char* fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vprintf_s(fmt, args);
    va_end(args);
};

static auto w_printf_s = [](const char* fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vprintf_s(fmt, args);
    va_end(args);
};

static auto w_sprintf = [](char* buf, const char* fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);
};

static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vsprintf_s(buf, buf_size, fmt, args);
    va_end(args);
};

#define XorStr( s ) ( XorCompileTime::XorString< sizeof( s ) - 1, __COUNTER__ >( s, std::make_index_sequence< sizeof( s ) - 1>() ).decrypt() )

END_NAMESPACE