winprefs v0.3.2
A registry exporter for programmers.
Loading...
Searching...
No Matches
powershell.c
1#include "powershell.h"
2#include "constants.h"
3#include "io.h"
4
5static wchar_t *escape_for_powershell(const wchar_t *input, size_t n_chars) {
6 wchar_t *out = nullptr;
7 if (input == nullptr || n_chars == 0) { // LCOV_EXCL_START
8 errno = EINVAL;
9 return nullptr;
10 } // LCOV_EXCL_STOP
11 unsigned i, j;
12 size_t new_n_chars = 0;
13 for (i = 0; i < n_chars; i++) {
14 new_n_chars++;
15 // Last condition is to handle REG_MULTI_SZ string sets
16 if (input[i] == L'\'') {
17 new_n_chars++;
18 }
19 }
20 out = calloc(new_n_chars + 1, WL);
21 if (!out) { // LCOV_EXCL_START
22 return nullptr;
23 } // LCOV_EXCL_STOP
24 wmemset(out, L'\0', new_n_chars + 1);
25 if (n_chars == new_n_chars) {
26 wmemcpy(out, input, new_n_chars + 1);
27 return out;
28 }
29 for (i = 0, j = 0; i < n_chars && j < new_n_chars; i++, j++) {
30 out[j] = input[i];
31 if (input[i] == L'\'') {
32 out[++j] = input[i];
33 }
34 }
35 return out;
36}
37
38static wchar_t *convert_data_for_powershell(DWORD reg_type, const char *data, size_t data_len) {
39 wchar_t *out, *bin, *strings_nl, *escaped;
40 out = bin = strings_nl = escaped = nullptr;
41 if (reg_type == REG_BINARY) {
42 size_t i;
43 int j;
44 size_t n_bin_chars = 5 * data_len;
45 size_t new_len = n_bin_chars + 1;
46 bin = calloc(new_len, WL);
47 if (!bin) { // LCOV_EXCL_START
48 goto fail;
49 } // LCOV_EXCL_STOP
50 wmemset(bin, L'\0', new_len);
51 for (i = 0, j = 0; i < data_len; i++) {
52 if (i < (data_len - 1)) {
53 wchar_t conv[6];
54 _snwprintf(conv, 6, L"0x%02X,", data[i] & 0xFF);
55 conv[5] = L'\0';
56 wcsncat(bin + j, conv, 5);
57 j += 5;
58 } else {
59 wchar_t conv[5];
60 _snwprintf(conv, 4, L"0x%02X", data[i] & 0xFF);
61 conv[4] = L'\0';
62 wcsncat(bin + j, conv, 4);
63 j += 4;
64 }
65 }
66 size_t s_size = new_len + 10;
67 out = calloc(s_size, WL);
68 if (!out) { // LCOV_EXCL_START
69 return nullptr;
70 } // LCOV_EXCL_STOP
71 wmemset(out, L'\0', s_size);
72 _snwprintf(out, s_size, L"(byte[]](%ls))", bin);
73 goto cleanup;
74 }
75 if (reg_type == REG_EXPAND_SZ || reg_type == REG_SZ) {
76 escaped = escape_for_powershell((wchar_t *)data, data_len == 0 ? 0 : data_len / WL);
77 if (!escaped) { // LCOV_EXCL_START
78 goto fail;
79 } // LCOV_EXCL_STOP
80 size_t escaped_len = wcslen(escaped);
81 size_t total_size = escaped_len + 3;
82 out = calloc(total_size, WL);
83 if (!out) { // LCOV_EXCL_START
84 goto fail;
85 } // LCOV_EXCL_STOP
86 wmemset(out, L'\0', total_size);
87 _snwprintf(out, escaped_len + 2, L"'%ls'", escaped);
88 goto cleanup;
89 }
90 if (reg_type == REG_MULTI_SZ) {
91 wchar_t *w_data = (wchar_t *)data;
92 size_t w_data_len = (data_len % WL == 0) ? data_len / WL : (data_len / WL) + 1;
93 size_t real_len = determine_multi_sz_size(w_data, w_data_len);
94 if (real_len > 2) {
95 size_t total_size = 9 + real_len;
96 out = calloc(total_size, WL);
97 if (!out) { // LCOV_EXCL_START
98 goto fail;
99 } // LCOV_EXCL_STOP
100 wmemset(out, L'\0', total_size);
101 strings_nl = calloc(w_data_len, WL);
102 if (!strings_nl) { // LCOV_EXCL_START
103 goto fail;
104 } // LCOV_EXCL_STOP
105 wmemset(strings_nl, L'\0', w_data_len);
106 size_t i;
107 for (i = 0; i < w_data_len - 2; i++) {
108 strings_nl[i] = w_data[i] == L'\0' ? L'\n' : w_data[i];
109 }
110 _snwprintf(out, total_size, L"@\"\n%ls\n\"@", strings_nl);
111 goto cleanup;
112 }
113 debug_print(L"Skipping incorrectly stored MultiString (length = %lu).\n", w_data_len);
114 goto fail;
115 }
116 if (reg_type == REG_DWORD) {
117 int req_size = _snwprintf(nullptr, 0, L"%lu", *(DWORD *)data);
118 out = calloc((size_t)(req_size + 1), WL);
119 if (!out) { // LCOV_EXCL_START
120 goto fail;
121 } // LCOV_EXCL_STOP
122 wmemset(out, L'\0', (size_t)(req_size + 1));
123 _snwprintf(out, (size_t)req_size, L"%lu", *(DWORD *)data);
124 goto cleanup;
125 }
126 if (reg_type == REG_QWORD) {
127 int req_size = _snwprintf(nullptr, 0, L"%llu", *(UINT64 *)data);
128 out = calloc((size_t)(req_size + 1), WL);
129 if (!out) { // LCOV_EXCL_START
130 goto fail;
131 } // LCOV_EXCL_STOP
132 wmemset(out, 0, (size_t)req_size);
133 _snwprintf(out, (size_t)req_size, L"%llu", *(UINT64 *)data);
134 goto cleanup;
135 }
136 errno = EINVAL;
137fail:
138 free(out);
139cleanup:
140 free(bin);
141 free(escaped);
142 free(strings_nl);
143 return out;
144}
145
146static wchar_t *add_colon_if_required(const wchar_t *path) {
147 wchar_t *escaped_reg_key, *full_path_ps, *top_key;
148 escaped_reg_key = full_path_ps = top_key = nullptr;
149 size_t full_path_len = wcslen(path) + 2;
150 full_path_ps = calloc(full_path_len, WL);
151 if (!full_path_ps) { // LCOV_EXCL_START
152 goto fail;
153 } // LCOV_EXCL_STOP
154 wmemset(full_path_ps, L'\0', full_path_len);
155 wchar_t *first_backslash = wcschr(path, '\\');
156 if (!first_backslash) {
157 goto fail;
158 }
159 size_t top_key_len = (size_t)((first_backslash - path) + 1);
160 top_key = calloc(top_key_len, WL);
161 if (!top_key) { // LCOV_EXCL_START
162 goto fail;
163 } // LCOV_EXCL_STOP
164 wmemset(top_key, L'\0', top_key_len);
165 wmemcpy(top_key, path, top_key_len - 1);
166 _snwprintf(full_path_ps, full_path_len, L"%ls:%ls", top_key, first_backslash);
167 full_path_ps[full_path_len - 1] = L'\0';
168 escaped_reg_key = escape_for_powershell(full_path_ps, wcslen(full_path_ps));
169 goto cleanup;
170fail:
171 escaped_reg_key = nullptr;
172cleanup:
173 free(full_path_ps);
174 free(top_key);
175 return escaped_reg_key;
176}
177
178bool do_write_powershell_reg_code(writer_t *writer,
179 const wchar_t *full_path,
180 const wchar_t *prop,
181 const char *value,
182 size_t data_len,
183 unsigned long type) {
184 wchar_t *out = nullptr;
185 wchar_t *escaped_d = convert_data_for_powershell(type, value, data_len);
186 wchar_t *escaped_reg_key = add_colon_if_required(full_path);
187 wchar_t *escaped_prop = escape_for_powershell(prop, wcslen(prop));
188 bool ret = true;
189 if (!escaped_reg_key) {
190 goto fail;
191 }
192 if (type == REG_MULTI_SZ && !escaped_d) {
193 goto cleanup;
194 }
195 wchar_t reg_type[14];
196 memset(reg_type, 0, sizeof(reg_type));
197 switch (type) {
198 case REG_NONE:
199 wcsncpy(reg_type, L"None", 4);
200 break;
201 case REG_BINARY:
202 wcsncpy(reg_type, L"Binary", 6);
203 break;
204 case REG_SZ:
205 wcsncpy(reg_type, L"String", 6);
206 break;
207 case REG_EXPAND_SZ:
208 wcsncpy(reg_type, L"ExpandString", 12);
209 break;
210 case REG_MULTI_SZ:
211 wcsncpy(reg_type, L"MultiString", 11);
212 break;
213 case REG_DWORD:
214 wcsncpy(reg_type, L"DWord", 5);
215 break;
216 case REG_QWORD:
217 wcsncpy(reg_type, L"Qword", 5);
218 break;
219 default: // LCOV_EXCL_START
220 goto cleanup;
221 // LCOV_EXCL_STOP
222 }
223 int req_size = _snwprintf(nullptr,
224 0,
225 POWERSHELL_CODE_TEMPLATE,
226 escaped_reg_key,
227 escaped_reg_key,
228 escaped_reg_key,
229 escaped_prop ? escaped_prop : L"",
230 reg_type,
231 escaped_d ? escaped_d : L"$null");
232 if ((size_t)req_size < POWERSHELL_MAX_COMMAND_LENGTH) {
233 out = calloc((size_t)req_size + 1, WL);
234 if (!out) { // LCOV_EXCL_START
235 goto fail;
236 } // LCOV_EXCL_STOP
237 wmemset(out, L'\0', (size_t)req_size + 1);
238 _snwprintf(out,
239 (size_t)req_size,
240 POWERSHELL_CODE_TEMPLATE,
241 escaped_reg_key,
242 escaped_reg_key,
243 escaped_reg_key,
244 escaped_prop ? escaped_prop : L"",
245 reg_type,
246 escaped_d ? escaped_d : L"$null");
247 ret = write_output(out, false, writer);
248 } else {
249 debug_print(L"%ls %ls: Skipping due to length of command.\n", full_path, prop);
250 }
251 goto cleanup;
252fail:
253 ret = false;
254cleanup:
255 free(escaped_d);
256 free(escaped_prop);
257 free(escaped_reg_key);
258 free(out);
259 return ret;
260}