0%

【Linux技术分享】密码输入框显示明文问题分析

密码输入框显示明文问题分析

现场环境

wine版本: wine10.14
系统版本:debian12

问题描述

  1. 密码输入框显示明文,如下图:
    图1

分析流程

  1. window下实现密码框通常设置window窗口ES_PASSWORD风格实现或者在wm_create中发送EM_SETPASSWORDCHAR消息设置window的edit为密码框

  2. 使用spy++发现wine下窗口风格与window下不一致,缺少ES_PASSWORD风格

  3. 查看msg/edit/win中逻辑,完成window下的demo,确认wine下的多行ES_MULTILINE风格不支持加密,该应用加密逻辑大致如下:

    • 该应用使用的是wingding.ttf中的字母l设置密码为黑圆圈。
    • 在WM_CREATE中发送消息类似SendMessage(hPwd, EM_SETPASSWORDCHAR, ‘*’, 0),由于用的是l字母所有这里发送的消息字符就是l
    • wingding这个字体wine中会自带,目前将window下的这个字体拷贝到容器中输入字符就会变化,目前原因还需要调研????
    • 在设置密码为黑圆圈的时候有两种方案,1:将WCHAR消息进行拦截,在这进行修改,2:类似步骤2,在wm_create中发送一次EM_SETPASSWORDCHAR消息即可设置
    • wine下收到EM_SETPASSWORDCHAR消息的时候,会在EDIT_EM_SetPasswordChar函数进程处理,目前就是这里出问题,在wine中当edit窗口中风格有ES_MULTILINE直接返回,不会设置edit为密码窗口
    • EDIT_EM_SetPasswordChar修改后还需要修改排版函数,不然输入的字符变成wingding.ttf对应的符号,不是密码中的字符,所以需要修改EDIT_UpdateUniscribeData_linedef函数
  4. 查看wine下的user32/edit.c中的EDIT_EM_SetPasswordChar函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c)
{
LONG style;

if (es->style & ES_MULTILINE)
return;

if (es->password_char == c)
return;

style = GetWindowLongW( es->hwndSelf, GWL_STYLE );
es->password_char = c;
if (c) {
SetWindowLongW( es->hwndSelf, GWL_STYLE, style | ES_PASSWORD );
es->style |= ES_PASSWORD;
} else {
SetWindowLongW( es->hwndSelf, GWL_STYLE, style & ~ES_PASSWORD );
es->style &= ~ES_PASSWORD;
}
EDIT_InvalidateUniscribeData(es);
EDIT_UpdateText(es, NULL, TRUE);
}
  1. 需要将EDIT_UpdateUniscribeData函数的EDIT_UpdateUniscribeData_linedef函数进行处理,第一个函数是处理单行的,第二个函数是处理编辑框多行风格的。在单行风格中有处理wine密码风格,让其显示密码型号,多行中没有,需要增加该逻辑,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    static SCRIPT_STRING_ANALYSIS EDIT_UpdateUniscribeData_linedef(EDITSTATE *es, HDC dc, LINEDEF *line_def)
    {
    if (!line_def)
    return NULL;

    if (line_def->net_length && !line_def->ssa)
    {
    int index = line_def->index;
    HFONT old_font = NULL;
    HDC udc = dc;
    SCRIPT_TABDEF tabdef;
    HRESULT hr;

    if (!udc)
    udc = NtUserGetDC(es->hwndSelf);
    if (es->font)
    old_font = SelectObject(udc, es->font);

    tabdef.cTabStops = es->tabs_count;
    tabdef.iScale = GdiGetCharDimensions(udc, NULL, NULL);
    tabdef.pTabStops = es->tabs;
    tabdef.iTabOrigin = 0;

    if (es->style & ES_PASSWORD)
    hr = ScriptStringAnalyse(udc, &es->password_char, line_def->net_length,
    (1.5*line_def->net_length+16), -1,
    SSA_LINK|SSA_FALLBACK|SSA_GLYPHS|SSA_TAB|SSA_PASSWORD, -1,
    NULL, NULL, NULL, &tabdef, NULL, &line_def->ssa);
    else
    hr = ScriptStringAnalyse(udc, &es->text[index], line_def->net_length,
    (1.5*line_def->net_length+16), -1,
    SSA_LINK|SSA_FALLBACK|SSA_GLYPHS|SSA_TAB, -1,
    NULL, NULL, NULL, &tabdef, NULL, &line_def->ssa);

    if (FAILED(hr))
    {
    WARN("ScriptStringAnalyse failed (%lx)\n",hr);
    line_def->ssa = NULL;
    }

    if (es->font)
    SelectObject(udc, old_font);
    if (udc != dc)
    NtUserReleaseDC( es->hwndSelf, udc );
    }

    return line_def->ssa;
    }

  2. 修改后成功显示黑圆圈
    图2