0

我正在尝试通过系统插件和netapi32库从 Windows 获取一些信息。

我尝试NetWkstaGetInfo()在分配一个适合作为WKSTA_INFO_100.

MSDN 中的NetWkstaGetInfo()原型状态:

NET_API_STATUS NetWkstaGetInfo(
  _In_   LPWSTR servername,
  _In_   DWORD level,
  _Out_  LPBYTE *bufptr
);

虽然WKSTA_INFO_100

typedef struct _WKSTA_INFO_100 {
  DWORD wki100_platform_id;
  LMSTR wki100_computername;
  LMSTR wki100_langroup;
  DWORD wki100_ver_major;
  DWORD wki100_ver_minor;
} WKSTA_INFO_100, *PWKSTA_INFO_100, *LPWKSTA_INFO_100;

对于初步测试,我尝试在消息框中显示结构成员。我首先使用虚拟信息初始化结构,以检查 api 调用是否替换了我分配的块的内容。

但是直到现在我在第一个结构成员之后几乎什么都没有,我想结构没有正确定义,或者我有结构对齐问题。不幸的是,系统插件的怪异文档让我发疯,对我没有多大帮助。

这是我的测试脚本:

outfile "hello.exe"

section

System::Call /NOUNLOAD "*(*i11,t 'some',t 'thing',i22,i44)i .r0"
Dumpstate::debug
System::Call /NOUNLOAD "netapi32::NetWkstaGetInfo(i0, i100, i r0) i.r6"
Dumpstate::debug
System::Call /NOUNLOAD "*$0(*i.r1, t.r2, t.r3, i.r4, i.r5)"
Dumpstate::debug
messagebox MB_OK "Hello, to $2 $3 domain (win $1 - $4.$5) !"
System::Free $0

sectionEnd

第一个检索到的值 (500) 是正确的。但其他成员保持其初始值。我错过了什么?

(编辑)推论问题:

  • 似乎按照文档和MSDN,结构的第一个成员应该是i而不是*i但我没有设法获得正确的返回值*(Dumpstate插件倾向于显示它作为地址返回)
  • /NOUNLOAD插件的参数是强制性的吗?我找到了几个例子,但没有找到确切的原因。我担心如果没有参数,分配的结构可能会被过早释放。你能确认/确认吗?
4

2 回答 2

0

似乎按照文档和MSDN,结构的第一个成员应该是i而不是*i但我没有设法获得正确的返回值*(Dumpstate插件倾向于显示它作为地址返回)

那是解决方案的线索:我误读了 MSDN 页面,起初并没有注意到它不是传递给的结构,NetWkstaGetInfo 而是由 api 调用修改的 a 的地址NetWkstaGetInfo*(并且必须在 by 之后释放NetApiBufferFree。因此正确的脚本是:

outfile "hello.exe"

section

System::Call  "netapi32::NetWkstaGetInfo(i0, i100, *i r0 r0) i.r6"
System::Call  "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)"
messagebox MB_OK "Hello, to $2 $3 domain (win $1 - $4.$5) !"
System::Call  "netapi32::NetApiBufferFree(*i r0) i.r6"

sectionEnd
于 2012-09-10T15:19:01.003 回答
0

bufptr 仅用于将 r0 作为输入传递给 NetWkstaGetInfo 是没有意义的,该函数不需要输入数据。您不应该*i与 NetApiBufferFree 一起使用,i单独使用就足够了($0 已经有地址,您不希望系统插件玩指针,只需将其直接传递给 API)

!include LogicLib.nsh

System::Call "netapi32::NetWkstaGetInfo(i0, i100, *i 0 r0) i.r1"
${If} 0 = $1
    System::Call "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)"
    DetailPrint "Hello, to $2 $3 domain (win $1 - $4.$5) !"
${EndIf}
System::Call "netapi32::NetApiBufferFree(ir0)"

在前面的示例中,我使用*i 0 r0了 bufptr 参数,以便在函数启动之前 $0 为 NULL(如果您不想使用此技巧,您可以StrCpy $0 0在系统调用之前执行)。如果你不这样做,那么如果函数失败会发生什么就不清楚了。文档没有指定当函数失败时 bufptr 会发生什么,希望它设置为 NULL 但你不能确定。如果函数失败,我们最终将 NULL 传递给 NetApiBufferFree,这通常是安全的传递给自由函数,但文档并未将其称为 OK。为了超级安全,你应该只释放一个非空指针:

System::Call "netapi32::NetWkstaGetInfo(i0, i100, *i 0 r0) i.r1"
${If} 0 = $1
    System::Call "*$0(i.r1, w.r2, w.r3, i.r4, i.r5)"
    DetailPrint "Hello, to $2 $3 domain (win $1 - $4.$5) !"
${EndIf}
${IfThen} $0 <> 0 ${|} System::Call "netapi32::NetApiBufferFree(ir0)" ${|}
SectionEnd

使用系统插件时不再需要 /NOUNLOAD(自 v2.42 起)。/NOUNLOAD 阻止 NSIS 卸载插件。如果插件具有内部状态,这一点很重要,但在您的情况下,唯一的状态是 Windows 分配的一块内存。

于 2012-09-10T19:28:08.520 回答