【问题标题】:Convert ASCII to unicode string in C/C++ (APIless)在 C/C++ 中将 ASCII 转换为 unicode 字符串(无 API)
【发布时间】:2020-05-22 07:54:08
【问题描述】:

我知道我 can 使用 MultiByteToWideChar 将 ASCII 转换为 unicode 字符串,但我想要一个无 API 的解决方案。唯一的区别是 unicode 是 2 个字节,而 ASCII 是 1 个。

应该是下面这样的,但是不行。

问题是:

void* __malloc(size_t size)
{
   return HeapAlloc(GetProcessHeap(), 0, size); 
}

void __free(void* p)
{
   if (p) HeapFree(GetProcessHeap(), 0, p); 
}

wchar_t* ascii_to_unicode(const char* ascii)
{
    if (!ascii)
        return nullptr;

    size_t len;
    wchar_t* unicode;

    len = strlen(ascii) * 2 + 1;
    if (!(unicode = reinterpret_cast<wchar_t*>(__malloc(len))))
        return nullptr;

    for (size_t i = 0; i < len; i++)
        *unicode++ = static_cast<wchar_t>(*ascii++);

    return unicode;
}

char* unicode_to_ascii(const wchar_t* unicode)
{
    if (!unicode)
        return nullptr;

    size_t len;
    char* ascii;

    len = wcslen(unicode) / 2 + 1;
    if (!(ascii = reinterpret_cast<char*>(__malloc(len))))
        return nullptr;

    for (size_t i = 0; i < len; i++)
        *ascii++ = static_cast<char>(*unicode++);

    return ascii;
}

我想将 strdup 返回的 ASCII 转换为我的自定义 get_module_handle 函数。

char* forwardLib = strdup(address);
char* forwardName = _strchr(forwardLib, '.');
*forwardName++ = 0;

get_module_handle(ascii_to_unicode(forwardLib));

//
void* get_module_handle(const wchar_t* moduleName)
{
#if defined _M_IX86
    PPEB pPEB = reinterpret_cast<PPEB>(__readfsdword(0x30));
#elif defined _M_X64
    PPEB pPEB = reinterpret_cast<PPEB>(__readgsqword(0x60));
#endif

    for (PLIST_ENTRY pListEntry = pPEB->Ldr->InMemoryOrderModuleList.Flink; pListEntry && pListEntry != &pPEB->Ldr->InMemoryOrderModuleList; pListEntry = pListEntry->Flink)
    {
        PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);

        if (!__wcsicmp(pLdrDataTableEntry->BaseDllName.Buffer, moduleName))
            return pLdrDataTableEntry->DllBase;
    }

    return nullptr;
}

【问题讨论】:

  • 你的代码无效 C.
  • @pmg,添加了 C++ 标签,因为我喜欢 nullptr 和演员表。
  • 无 API 解决方案 -- 是否包括跨平台解决方案?您应该考虑是否要亲自进行这些转换。另外,为什么是指针,而不是从std::stringstd::wstring 转换为/?鉴于您要完成的工作,您的方法是使用 std::copystd::transform 的简单 1 或 2 行函数。
  • @PaulMcKenzie,我不想使用 CRT。我正在使用/NODEFAULTLIB
  • 你也想转换什么 unicode 标准?如果是 UTF-8,则不需要转换,因为所有 ascii 值在 UTF-8 中都是有效的。

标签: c++ unicode shellcode


【解决方案1】:

唯一的区别是unicode是2个字节,而ASCII是1个。

“Unicode”是一个标准。 Windows 为了简化事情而称之为“Unicode”实际上是 Unicode 标准指定的 UTF-16LE 字符编码。还有其他字符编码,例如 UTF-32BE、UTF-32LE、UTF-8 和 UTF-16BE。对于 UTF-16 和 UTF-32,如果没有指定字节序,“字节顺序标记”通常用于区分数据是大字节序(BE;U+005A -&gt; 00 5A)还是小字节序(LE;U+005A -&gt; 5A 00)。

对于 UTF-8,字节顺序无关紧要,但某些程序(例如 Windows 记事本)无论如何都会添加字节顺序标记。许多程序不喜欢这样,在记事本中保存 UTF-8 XML 数据会导致 XML 格式错误,因为在 XML prolog 之前不能出现任何字节。有关 Unicode 的更多信息,我强烈建议阅读The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

解决您的实际问题,所有 ASCII 字符(十六进制代码 0x00..0x7F)在 UTF-16LE 中都是相同的,除了 ASCII 字符后有一个 '\0' 字节:

C       ASCII code  UTF-16LE bytes
'z'     7A          7A 00
'K'     4B          4B 00
'\0'    00          00 00
'\n'    0A          0A 00
'\x7F'  7F          7F 00

小于 0 或大于 0x7F 的任何内容都不是 ASCII,需要您知道字节代表什么以及相应的 Unicode 代码点。例如,这里是在各种 Windows 代码页中解释的相同字节 0xB9:

Code page  Char  Unicode code point
932        ケ     U+FF79
1251       №     U+2116
1252       ¹     U+00B9

这对于像 932 这样的代码页来说尤其成问题,有时需要多个字节来表达一个字符。由于这个问题,如果您要避免使用MultiByteToWideChar,那么您的程序需要拒绝任何不是 ASCII 的内容。否则,您必须使用MultiByteToWideChar

【讨论】:

    【解决方案2】:

    你应该尽量简化你的方法:

    • 请勿使用malloc 或任何系统特定头像。
    • 尽量避免转换字符串,直接处理 char 数组和 UTF16LE 数组,但编写您自己的函数来执行此操作并内联它们。
    • 如果确实需要转换,请使用自动数组。

    如果您的目标是修复它们,那么剖析软件以发现缺陷是诱人且有用的。利用软件缺陷在游戏中作弊或破解软件保护方案是恶意软件的一种形式,尤其是当您分享您的成就时。用你的技能来生产有价值的软件。

    【讨论】:

      猜你喜欢
      • 2012-07-19
      • 2018-03-21
      • 2020-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多