| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome_elf/nt_registry/nt_registry.h" | 5 #include "chrome_elf/nt_registry/nt_registry.h" |
| 6 | 6 |
| 7 #include <assert.h> | 7 #include <assert.h> |
| 8 #include <stdlib.h> | 8 #include <stdlib.h> |
| 9 | 9 |
| 10 #include <memory> |
| 11 |
| 10 namespace { | 12 namespace { |
| 11 | 13 |
| 12 // Function pointers used for registry access. | 14 // Function pointers used for registry access. |
| 13 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; | 15 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr; |
| 14 NtCreateKeyFunction g_nt_create_key = nullptr; | 16 NtCreateKeyFunction g_nt_create_key = nullptr; |
| 15 NtDeleteKeyFunction g_nt_delete_key = nullptr; | 17 NtDeleteKeyFunction g_nt_delete_key = nullptr; |
| 16 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; | 18 NtOpenKeyExFunction g_nt_open_key_ex = nullptr; |
| 17 NtCloseFunction g_nt_close = nullptr; | 19 NtCloseFunction g_nt_close = nullptr; |
| 18 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; | 20 NtQueryValueKeyFunction g_nt_query_value_key = nullptr; |
| 19 NtSetValueKeyFunction g_nt_set_value_key = nullptr; | 21 NtSetValueKeyFunction g_nt_set_value_key = nullptr; |
| (...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 535 out_base->push_back(L'\\'); | 537 out_base->push_back(L'\\'); |
| 536 } | 538 } |
| 537 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); | 539 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); |
| 538 } else { | 540 } else { |
| 539 out_base->assign(converted_root); | 541 out_base->assign(converted_root); |
| 540 } | 542 } |
| 541 | 543 |
| 542 return true; | 544 return true; |
| 543 } | 545 } |
| 544 | 546 |
| 547 // String safety. |
| 548 // - NOTE: only working with wchar_t here. |
| 549 // - Also ensures the content of |value_bytes| is at least a terminator. |
| 550 // - Pass "true" for |multi| for MULTISZ. |
| 551 void EnsureTerminatedSZ(std::vector<BYTE>* value_bytes, bool multi) { |
| 552 DWORD terminator_size = sizeof(wchar_t); |
| 553 |
| 554 if (multi) |
| 555 terminator_size = 2 * sizeof(wchar_t); |
| 556 |
| 557 // Ensure content is at least the size of a terminator. |
| 558 if (value_bytes->size() < terminator_size) { |
| 559 value_bytes->insert(value_bytes->end(), |
| 560 terminator_size - value_bytes->size(), 0); |
| 561 } |
| 562 |
| 563 // Sanity check content size based on character size. |
| 564 DWORD modulo = value_bytes->size() % sizeof(wchar_t); |
| 565 value_bytes->insert(value_bytes->end(), modulo, 0); |
| 566 |
| 567 // Now finally check for trailing terminator. |
| 568 bool terminated = true; |
| 569 size_t last_element = value_bytes->size() - 1; |
| 570 for (size_t i = 0; i < terminator_size; i++) { |
| 571 if ((*value_bytes)[last_element - i] != 0) { |
| 572 terminated = false; |
| 573 break; |
| 574 } |
| 575 } |
| 576 |
| 577 if (terminated) |
| 578 return; |
| 579 |
| 580 // Append a full terminator to be safe. |
| 581 value_bytes->insert(value_bytes->end(), terminator_size, 0); |
| 582 |
| 583 return; |
| 584 } |
| 585 |
| 545 //------------------------------------------------------------------------------ | 586 //------------------------------------------------------------------------------ |
| 546 // Misc wrapper functions - LOCAL | 587 // Misc wrapper functions - LOCAL |
| 547 //------------------------------------------------------------------------------ | 588 //------------------------------------------------------------------------------ |
| 548 | 589 |
| 549 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, | 590 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, |
| 550 ACCESS_MASK access, | 591 ACCESS_MASK access, |
| 551 HANDLE* out_handle, | 592 HANDLE* out_handle, |
| 552 ULONG* create_or_open OPTIONAL) { | 593 ULONG* create_or_open OPTIONAL) { |
| 553 UNICODE_STRING key_path_uni = {}; | 594 UNICODE_STRING key_path_uni = {}; |
| 554 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); | 595 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 g_nt_close(key); | 783 g_nt_close(key); |
| 743 } | 784 } |
| 744 | 785 |
| 745 //------------------------------------------------------------------------------ | 786 //------------------------------------------------------------------------------ |
| 746 // Getter functions | 787 // Getter functions |
| 747 //------------------------------------------------------------------------------ | 788 //------------------------------------------------------------------------------ |
| 748 | 789 |
| 749 bool QueryRegKeyValue(HANDLE key, | 790 bool QueryRegKeyValue(HANDLE key, |
| 750 const wchar_t* value_name, | 791 const wchar_t* value_name, |
| 751 ULONG* out_type, | 792 ULONG* out_type, |
| 752 BYTE** out_buffer, | 793 std::vector<BYTE>* out_buffer) { |
| 753 DWORD* out_size) { | |
| 754 if (!g_initialized) | 794 if (!g_initialized) |
| 755 InitNativeRegApi(); | 795 InitNativeRegApi(); |
| 756 | 796 |
| 757 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; | 797 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; |
| 758 UNICODE_STRING value_uni = {}; | 798 UNICODE_STRING value_uni = {}; |
| 759 g_rtl_init_unicode_string(&value_uni, value_name); | 799 g_rtl_init_unicode_string(&value_uni, value_name); |
| 760 DWORD size_needed = 0; | 800 DWORD size_needed = 0; |
| 761 bool success = false; | |
| 762 | 801 |
| 763 // First call to find out how much room we need for the value! | 802 // First call to find out how much room we need for the value! |
| 764 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, | 803 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, |
| 765 nullptr, 0, &size_needed); | 804 nullptr, 0, &size_needed); |
| 766 if (ntstatus != STATUS_BUFFER_TOO_SMALL) | 805 if (ntstatus != STATUS_BUFFER_TOO_SMALL) |
| 767 return false; | 806 return false; |
| 768 | 807 |
| 808 std::unique_ptr<BYTE[]> buffer(new BYTE[size_needed]); |
| 769 KEY_VALUE_FULL_INFORMATION* value_info = | 809 KEY_VALUE_FULL_INFORMATION* value_info = |
| 770 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(new BYTE[size_needed]); | 810 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(buffer.get()); |
| 771 | 811 |
| 772 // Second call to get the value. | 812 // Second call to get the value. |
| 773 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, | 813 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, |
| 774 value_info, size_needed, &size_needed); | 814 value_info, size_needed, &size_needed); |
| 775 if (NT_SUCCESS(ntstatus)) { | 815 if (!NT_SUCCESS(ntstatus)) |
| 776 *out_type = value_info->Type; | 816 return false; |
| 777 *out_size = value_info->DataLength; | 817 |
| 778 *out_buffer = new BYTE[*out_size]; | 818 *out_type = value_info->Type; |
| 779 ::memcpy(*out_buffer, | 819 DWORD data_size = value_info->DataLength; |
| 780 (reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset), | 820 |
| 781 *out_size); | 821 if (data_size) { |
| 782 success = true; | 822 // Move the data into |out_buffer| vector. |
| 823 BYTE* data = reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset; |
| 824 out_buffer->assign(data, data + data_size); |
| 825 } else { |
| 826 out_buffer->clear(); |
| 783 } | 827 } |
| 784 | 828 |
| 785 delete[] value_info; | 829 return true; |
| 786 return success; | |
| 787 } | 830 } |
| 788 | 831 |
| 789 // wrapper function | 832 // wrapper function |
| 790 bool QueryRegValueDWORD(HANDLE key, | 833 bool QueryRegValueDWORD(HANDLE key, |
| 791 const wchar_t* value_name, | 834 const wchar_t* value_name, |
| 792 DWORD* out_dword) { | 835 DWORD* out_dword) { |
| 793 ULONG type = REG_NONE; | 836 ULONG type = REG_NONE; |
| 794 BYTE* value_bytes = nullptr; | 837 std::vector<BYTE> value_bytes; |
| 795 DWORD ret_size = 0; | |
| 796 | 838 |
| 797 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || | 839 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) || |
| 798 type != REG_DWORD) | 840 type != REG_DWORD) { |
| 841 return false; |
| 842 } |
| 843 |
| 844 if (value_bytes.size() < sizeof(*out_dword)) |
| 799 return false; | 845 return false; |
| 800 | 846 |
| 801 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); | 847 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes.data())); |
| 802 | 848 |
| 803 delete[] value_bytes; | |
| 804 return true; | 849 return true; |
| 805 } | 850 } |
| 806 | 851 |
| 807 // wrapper function | 852 // wrapper function |
| 808 bool QueryRegValueDWORD(ROOT_KEY root, | 853 bool QueryRegValueDWORD(ROOT_KEY root, |
| 809 WOW64_OVERRIDE wow64_override, | 854 WOW64_OVERRIDE wow64_override, |
| 810 const wchar_t* key_path, | 855 const wchar_t* key_path, |
| 811 const wchar_t* value_name, | 856 const wchar_t* value_name, |
| 812 DWORD* out_dword) { | 857 DWORD* out_dword) { |
| 813 HANDLE key = INVALID_HANDLE_VALUE; | 858 HANDLE key = INVALID_HANDLE_VALUE; |
| 814 | 859 |
| 815 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) | 860 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
| 816 return false; | 861 return false; |
| 817 | 862 |
| 818 if (!QueryRegValueDWORD(key, value_name, out_dword)) { | 863 if (!QueryRegValueDWORD(key, value_name, out_dword)) { |
| 819 CloseRegKey(key); | 864 CloseRegKey(key); |
| 820 return false; | 865 return false; |
| 821 } | 866 } |
| 822 | 867 |
| 823 CloseRegKey(key); | 868 CloseRegKey(key); |
| 824 return true; | 869 return true; |
| 825 } | 870 } |
| 826 | 871 |
| 827 // wrapper function | 872 // wrapper function |
| 828 bool QueryRegValueSZ(HANDLE key, | 873 bool QueryRegValueSZ(HANDLE key, |
| 829 const wchar_t* value_name, | 874 const wchar_t* value_name, |
| 830 std::wstring* out_sz) { | 875 std::wstring* out_sz) { |
| 831 BYTE* value_bytes = nullptr; | 876 std::vector<BYTE> value_bytes; |
| 832 DWORD ret_size = 0; | |
| 833 ULONG type = REG_NONE; | 877 ULONG type = REG_NONE; |
| 834 | 878 |
| 835 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || | 879 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) || |
| 836 type != REG_SZ) | 880 (type != REG_SZ && type != REG_EXPAND_SZ)) { |
| 837 return false; | 881 return false; |
| 882 } |
| 838 | 883 |
| 839 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); | 884 EnsureTerminatedSZ(&value_bytes, false); |
| 840 | 885 |
| 841 delete[] value_bytes; | 886 *out_sz = reinterpret_cast<wchar_t*>(value_bytes.data()); |
| 887 |
| 842 return true; | 888 return true; |
| 843 } | 889 } |
| 844 | 890 |
| 845 // wrapper function | 891 // wrapper function |
| 846 bool QueryRegValueSZ(ROOT_KEY root, | 892 bool QueryRegValueSZ(ROOT_KEY root, |
| 847 WOW64_OVERRIDE wow64_override, | 893 WOW64_OVERRIDE wow64_override, |
| 848 const wchar_t* key_path, | 894 const wchar_t* key_path, |
| 849 const wchar_t* value_name, | 895 const wchar_t* value_name, |
| 850 std::wstring* out_sz) { | 896 std::wstring* out_sz) { |
| 851 HANDLE key = INVALID_HANDLE_VALUE; | 897 HANDLE key = INVALID_HANDLE_VALUE; |
| 852 | 898 |
| 853 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) | 899 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
| 854 return false; | 900 return false; |
| 855 | 901 |
| 856 if (!QueryRegValueSZ(key, value_name, out_sz)) { | 902 if (!QueryRegValueSZ(key, value_name, out_sz)) { |
| 857 CloseRegKey(key); | 903 CloseRegKey(key); |
| 858 return false; | 904 return false; |
| 859 } | 905 } |
| 860 | 906 |
| 861 CloseRegKey(key); | 907 CloseRegKey(key); |
| 862 return true; | 908 return true; |
| 863 } | 909 } |
| 864 | 910 |
| 865 // wrapper function | 911 // wrapper function |
| 866 bool QueryRegValueMULTISZ(HANDLE key, | 912 bool QueryRegValueMULTISZ(HANDLE key, |
| 867 const wchar_t* value_name, | 913 const wchar_t* value_name, |
| 868 std::vector<std::wstring>* out_multi_sz) { | 914 std::vector<std::wstring>* out_multi_sz) { |
| 869 BYTE* value_bytes = nullptr; | 915 std::vector<BYTE> value_bytes; |
| 870 DWORD ret_size = 0; | |
| 871 ULONG type = REG_NONE; | 916 ULONG type = REG_NONE; |
| 872 | 917 |
| 873 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || | 918 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) || |
| 874 type != REG_MULTI_SZ) | 919 type != REG_MULTI_SZ) { |
| 875 return false; | 920 return false; |
| 921 } |
| 876 | 922 |
| 877 // Make sure the vector is empty to start. | 923 EnsureTerminatedSZ(&value_bytes, true); |
| 878 (*out_multi_sz).resize(0); | |
| 879 | 924 |
| 880 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes); | 925 // Make sure the out vector is empty to start. |
| 926 out_multi_sz->clear(); |
| 927 |
| 928 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes.data()); |
| 881 std::wstring temp = pointer; | 929 std::wstring temp = pointer; |
| 882 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in | 930 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in |
| 883 // a row). | 931 // a row). |
| 884 while (temp.length() != 0) { | 932 while (!temp.empty()) { |
| 885 (*out_multi_sz).push_back(temp); | |
| 886 | |
| 887 pointer += temp.length() + 1; | 933 pointer += temp.length() + 1; |
| 934 out_multi_sz->push_back(std::move(temp)); |
| 888 temp = pointer; | 935 temp = pointer; |
| 889 } | 936 } |
| 890 | 937 |
| 891 // Handle the case of "empty multi_sz". | |
| 892 if (out_multi_sz->size() == 0) | |
| 893 out_multi_sz->push_back(L""); | |
| 894 | |
| 895 delete[] value_bytes; | |
| 896 return true; | 938 return true; |
| 897 } | 939 } |
| 898 | 940 |
| 899 // wrapper function | 941 // wrapper function |
| 900 bool QueryRegValueMULTISZ(ROOT_KEY root, | 942 bool QueryRegValueMULTISZ(ROOT_KEY root, |
| 901 WOW64_OVERRIDE wow64_override, | 943 WOW64_OVERRIDE wow64_override, |
| 902 const wchar_t* key_path, | 944 const wchar_t* key_path, |
| 903 const wchar_t* value_name, | 945 const wchar_t* value_name, |
| 904 std::vector<std::wstring>* out_multi_sz) { | 946 std::vector<std::wstring>* out_multi_sz) { |
| 905 HANDLE key = INVALID_HANDLE_VALUE; | 947 HANDLE key = INVALID_HANDLE_VALUE; |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1089 if (!g_initialized) | 1131 if (!g_initialized) |
| 1090 InitNativeRegApi(); | 1132 InitNativeRegApi(); |
| 1091 | 1133 |
| 1092 if (root == HKCU || (root == AUTO && !g_system_install)) | 1134 if (root == HKCU || (root == AUTO && !g_system_install)) |
| 1093 return g_HKCU_override; | 1135 return g_HKCU_override; |
| 1094 | 1136 |
| 1095 return g_HKLM_override; | 1137 return g_HKLM_override; |
| 1096 } | 1138 } |
| 1097 | 1139 |
| 1098 }; // namespace nt | 1140 }; // namespace nt |
| OLD | NEW |